Welcome back to another Java tutorial! If you are following along, then you just finished playing around with numbers in DrJava's interactions pane. In this tutorial, we will be giving some context to some of the examples from the previous tutorial. In particular, we'll be covering Java primitive types and their role in variable creation. Let's get started!\n\n\n\n\n\nConcepts\n\n\n\nBefore we really dig into the code, we need to talk about primitive types and their capabilities.\n\n\n\nJava Primitive Types\n\n\n\n\n\n\n\nIn every programming language, there are data types that are built-in to the language. In languages like Java where all data types are explicit, each one has a unique keyword. These explicit keywords are used to tell the language what type we want to use when we create variables:\n\n\n\nvariableType variableName; \/\/ Declaration\nvariableName = variableValue; \/\/ Definition\n\n\n\nThe syntax above is how we create and store data in a variable. We start by declaring the type of the data we want to store followed by its name. This portion of the syntax is called the variable declaration. Then, we define the variable using the assignment operator (=) and some value. Of course, it's much easier to create variables in a single line:\n\n\n\nvariableType variableName = variableValue;\n\n\n\nIn Java, we can define a variable using one of the eight built-in data types which we call primitive types: int, double, char, byte, short, long, float, and boolean. For example, we might define an integer as follows:\n\n\n\nint height = 17;\n\n\n\nIn this case, we've defined a variable called height with a value of 17. Naturally, we'll need to become familiar with all eight primitive types, so we can use them appropriately. \n\n\n\nJava Relational Operators\n\n\n\n\n\n\n\nJust above, we talked about storing a numeric value in a variable. That said, Java can do a lot more than store numbers. For example, we can compare numbers using the relational operators. \n\n\n\nIn the previous tutorial, we were exposed to one of these operators: ==. In addition, we can compare values using !=, <, <=, >, and >=. Try some of the following examples:\n\n\n\n6 > 7 \/\/ 6 is greater than 7 (false)\n110 >= 54 \/\/ 110 is greater than or equal to 54 (true)\n95 < 96 \/\/ 95 is less than 96 (true)\n63 <= 100 \/\/ 63 is less than or equal to 100 (true)\n\n\n\nAs you have probably noticed, the result of each of these operations is a boolean value: true or false. In the future, we will see these operators being used to drive all sorts of logic.\n\n\n\nJava Arithmetic Operators\n\n\n\n\n\n\n\nWhile the relational operators are fun, we need arithmetic operators to make our expressions more interesting. Up to this point, we have introduced arithmetic operators at random without really explaining them. Fortunately, we'll take a look at all of the most common Java arithmetic operators: +, -, *, \/, %.\n\n\n\nTo start, try running the following expressions and pay attention to the comments:\n\n\n\n2 + 3 \/\/ 2 plus 3 (5)\n11 - 5 \/\/ 11 minus 5 (6)\n13 * 2 \/\/ 13 times 2 (26)\n6 \/ 3 \/\/ 6 divided by 3 (2)\n11 % 2 \/\/ remainder of 11 divided by 2 (1)\n\n\n\nIn this case, we've executed all five operators on integers. It's a good idea to get familiar with what would happen if you ran each operator on the various primitive types. For example, try using the double type:\n\n\n\n2.0 + 3.0 \/\/ 2.0 plus 3.0 (5.0)\n11.0 - 5.0 \/\/ 11.0 minus 5.0 (6.0)\n13.0 * 2.0 \/\/ 13.0 times 2.0 (26.0)\n6.0 \/ 3.0 \/\/ 6.0 divided by 3.0 (2.0)\n11.0 % 2.0 \/\/ ERROR! Can't compute remainder on doubles\n\n\n\nAs we'll see in the next section, things get weird when we mix the types in our expressions. \n\n\n\nTruncation\n\n\n\nWhile arithmetic might seem straightforward, there are some pitfalls we should be aware of. After all, what do we expect to happen when we start to mix primitive types? For example, the following expressions return different results:\n\n\n\n1 + 2 \/\/ 3\n1 + 2.0 \/\/ 3.0\n\n\n\nIt might seem silly, but this distinction can have consequences. For instance, what happens if we swap addition for division? As it turns out, something like 1 \/ 2 will result in a value of 0. In computer science, we call this truncation.\n\n\n\nTruncation occurs because 32-bit integers can only hold discrete values. Instead of rounding the output, integers just drop any bits that do not fit in the 32-bit window. This is true for all of the data types, but it is often easier to notice with integers.\n\n\n\nWhile truncation can be confusing and counter-intuitive, it comes in handy in some instances such as mapping\u2014we will definitely be exposed to this later.\n\n\n\nAt any rate, as long as our types are consistent, arithmetic is pretty simple. However, if we are forced to mix compatible types such as integer and double, Java converts the entire result to the widest type. In other words, the type that has the most bits will be the result of the computation.\n\n\n\nNumeric Limits\n\n\n\nAnother potential issue with arithmetic is wraparound. As it turns out, numbers in computer systems have limits, and computations can sometimes exceed those limits. \n\n\n\nIf you had a chance to read up on the 8 primitive types, then you'll know that there's a quick way to check the limits of each primitive type. As a refresher, we can determine the maximum value of an integer using the following code snippet:\n\n\n\nInteger.MAX_VALUE\n\n\n\nThe return value might seem confusing at first, but we will quickly realize that the value is half of the possible range. That must mean the other half of the range is composed of negative values. Try using the following as confirmation:\n\n\n\nInteger.MIN_VALUE\n\n\n\nFor fun, let's see what happens when we push beyond these limits:\n\n\n\nInteger.MAX_VALUE + 1 \/\/ Prints -2147483648\nInteger.MIN_VALUE - 1 \/\/ Prints 2147483647\n\n\n\nIsn't that odd? We've just observed integer wraparound for the first time. In other words, once we've hit the limit of a primitive type, we'll wraparound to the other side. Keep that in mind as we move forward.\n\n\n\nIn case it wasn't already clear, a data type which has its range split between negative and positive values is called a signed type. Likewise, a data type which has an entirely positive range is called an unsigned typed. In either case, the language interprets the bits representing a value.\n\n\n\nType Casting\n\n\n\nPerhaps the last topic to touch on for primitive types is this notion of type casting. We already talked about type widening where a computation gets stored in the widest type. Type casting is just the opposite.\n\n\n\nLet's say we had a computation that would result in a double, but we did not care about the decimal result. We can cut the precision using a typecast to integer. This is used all over the place in code, but a good example would be an implementation of rounding. Without any knowledge of control flow, we can implement rounding:\n\n\n\nint round = (int) (7.6 + 0.5);\n\n\n\nIn this example, the number we are trying to round to the nearest whole number is 7.6. If the decimal is less than .5, we want the result to round down. Likewise, if the decimal is .5 or greater, we want the result to round-up.\n\n\n\nBy adding .5, we force 7.6 to become 8.1. The typecast then truncates the decimal point which results in our properly rounded integer. If the number was 7.4, the computation would force 7.4 to 7.9. Then the typecast would truncate the decimal.\n\n\n\nWith that in mind, we have covered just about everything we might need to know about the Java primitive types.\n\n\n\nPractice\n\n\n\nAt this point, we should be quite familiar with a handful of concepts including:\n\n\n\nVariable declarations and definitions8 primitive types: boolean, int, double, float, byte, short, long, char5 arithmetic operators: +, -, *, \/, %5 relational operators: ==, >=, >, <, <=TruncationType castingNumeric limits\n\n\n\nAt this point, we'll bring it all together with some examples. In the interactions pane, try the following:\n\n\n\nchar letter = 'b';\n\n\n\nEarlier, we wrote a similar line where we assigned a variable a value of 7. In that case we were working with integers. In this case, we are working with the char primitive type which can store character values. With this line, we have now stored our own value in a variable called letter. Go ahead and experiment with the various data types. For instance, we might try any of the following:\n\n\n\nboolean hasMoney = true; \nint hour = 7; \ndouble height = 13.7; \nfloat gravity = 9.81f; \nlong sixBillion = 6000000000L;\n\n\n\nNow that we have some variables declared, try adding some of these values together and note the results. For instance:\n\n\n\nhour + height;\n\n\n\nThe variable names do not make a lot of sense, but this is perfectly legal and will result in 20.7. However, if we try something like:\n\n\n\nhasMoney + hour;\n\n\n\nWe will end up with an error. That is because we're trying to add a boolean to an integer. Meanwhile, the following is completely legal in Java:\n\n\n\nchar gravity = 'g'; \nchar speedOfLight = 'c'; \ngravity + speedOfLight;\n\n\n\nWe can indeed add these characters together which yields 202 or '\u00ca'. Because the char type is actually a numeric value, we can sum them like integers.\n\n\n\nAdding characters is particularly handy if we want to compare characters for ordering. For instance, two letters can be compared alphabetically by comparing their numeric values. A complete list of all the available ASCII characters and there values can be found here.\n\n\n\nAs an added note, Java characters are 16-bit which gives them much greater variety than the 256 ASCII characters. In addition, the char primitive type is the only Java primitive type that is unsigned.\n\n\n\nBut What About Strings?\n\n\n\nSince we're on the topic of characters, let's talk strings. Java has native support for strings which are sequences of characters. However, strings are not a Java primitive type. They are instead a reference type.\n\n\n\nA reference type is a bit different from a primitive type. With primitive types, we are free to copy and compare data as needed. This makes development extremely intuitive because of this concept called value semantics. Value semantics imply that variables are immutable, so we don't have to worry about a copy corrupting the original value.\n\n\n\nTo test this concept, try the following in DrJava's interactions pane:\n\n\n\nint x = 5; \nint y = 5; \ny == x;\n\n\n\nNotice that this comparison returns true as expected. Intuitively, 5 equals 5. Now try the following:\n\n\n\nString firstName = "Leroy"; \nString lastName = "Leroy"; \nfirstName == lastName;\n\n\n\nIn this example, we define two components of someone's name: Leroy Leroy. Intuitively, we would think comparing both names would return true. After all, both names have the same letters and both names are case-sensitive. However, we get a shocking result of false.\n\n\n\nAs it turns out, the == operator does not compare the strings as expected. The reason for the bad comparison will be explained in more detail in the following tutorial, so for now try comparing more strings. For instance, we could try creating two strings and assigning them to each other:\n\n\n\nString firstName = "Leroy"; \nString lastName = "Jenkins"; \nfirstName = lastName; \nfirstName == lastName;\n\n\n\nIn this case, the comparison using == results in true. Of course, the value comparison is the same, so why would it return true this time? In the next tutorial, we will take a deeper look at strings and what is really happening when we make a comparison using ==.\n\n\n\nBe careful! If you use almost any tool other than DrJava's interactions pane, you may find that expressions like "Leroy" == "Leroy" return true. This is due to a special feature of Java called string interning (thanks, Iven) which ensures that duplicate string constants have the same reference. In other words, we still aren't comparing the contents of the string. More on that later!