Reviewing Primitive Assignments
See if you can figure out why each of the following lines does not compile:
int fish = 1.0; // DOES NOT COMPILE short bird = 1921222; // DOES NOT COMPILE int mammal = 9f; // DOES NOT COMPILE long reptile = 192_301_398_193_810_323; // DOES NOT COMPILE
The first statement does not compile because you are trying to assign a double 1.0
to an integer value. Even though the value is a mathematic integer, by adding .0
, you're instructing the compiler to treat it as a double
. The second statement does not compile because the literal value 1921222
is outside the range of short
, and the compiler detects this. The third statement does not compile because the f
added to the end of the number instructs the compiler to treat the number as a floating-point value, but the assignment is to an int
. Finally, the last statement does not compile because Java interprets the literal as an int
and notices that the value is larger than int
allows. The literal would need a postfix L
or l
to be considered a long
.
Applying Casting
We can fix three of the previous examples by casting the results to a smaller data type. Remember, casting primitives is required any time you are going from a larger numerical data type to a smaller numerical data type, or converting from a floating-point number to an integral value.
int fish = (int)1.0; short bird = (short)1921222; // Stored as 20678 int mammal = (int)9f;
What about applying casting to the last example?
long reptile = (long)192301398193810323; // DOES NOT COMPILE
This still does not compile because the value is first interpreted as an int
by the compiler and is out of range. The following fixes this code without requiring casting:
long reptile = 192301398193810323L;
Overflow and Underflow
The expressions in the previous example now compile, although there's a cost. The second value, 1,921,222
, is too large to be stored as a short
, so numeric overflow occurs, and it becomes 20,678
. Overflow is when a number is so large that it will no longer fit within the data type, so the system “wraps around” to the lowest negative value and counts up from there, similar to how modulus arithmetic works. There's also an analogous underflow, when the number is too low to fit in the data type, such as storing -200
in a byte
field.
This is beyond the scope of the exam but something to be careful of in your own code. For example, the following statement outputs a negative number:
System.out.print(2147483647+1); // -2147483648
Since 2147483647
is the maximum int
value, adding any strictly positive value to it will cause it to wrap to the smallest negative number.
Let's return to a similar example from the “Numeric Promotion” section earlier in the chapter.
short mouse = 10; short hamster = 3; short capybara = mouse * hamster; // DOES NOT COMPILE
Based on everything you have learned up until now about numeric promotion and casting, do you understand why the last line of this statement will not compile? As you may remember, short
values are automatically promoted to int
when applying any arithmetic operator, with the resulting value being of type int
. Trying to assign a short
variable with an int
value results in a compiler error, as Java thinks you are trying to implicitly convert from a larger data type to a smaller one.
We can fix this expression by casting, as there are times that you may want to override the compiler's default behavior. In this example, we know the result of 10 * 3
is 30
, which can easily fit into a short
variable, so we can apply casting to convert the result back to a short
:
short mouse = 10; short hamster = 3; short capybara = (short)(mouse * hamster);
By casting a larger value into a smaller data type, you instruct the compiler to ignore its default behavior. In other words, you are telling the compiler that you have taken additional steps to prevent overflow or underflow. It is also possible that in your particular application and scenario, overflow or underflow would result in acceptable values.
Last but not least, casting can appear anywhere in an expression, not just on the assignment. For example, let's take a look at a modified form of the previous example:
short mouse = 10; short hamster = 3; short capybara = (short)mouse * hamster; // DOES NOT COMPILE
So, what's happening on the last line? Well, remember when we said casting was a unary operation? That means the cast in the last line is applied to mouse
, and mouse
alone. After the cast is complete, both operands are promoted to int
since they are used with the binary multiplication operator (*
), making the result an int
and causing a compiler error.
What if we changed the last line to the following?
short capybara = 1 + (short)(mouse * hamster); // DOES NOT COMPILE
In the example, casting is performed successfully, but the resulting value is automatically promoted to int
because it is used with the binary arithmetic operator (+
).
Casting Values vs. Variables
Revisiting our third numeric promotional rule, the compiler doesn't require casting when working with literal values that fit into the data type. Consider these examples:
byte hat = 1; byte gloves = 7 * 10; short scarf = 5; short boots = 2 + 1;
All of these statements compile without issue. On the other hand, neither of these statements compiles:
short boots = 2 + hat; // DOES NOT COMPILE byte gloves = 7 * 100; // DOES NOT COMPILE
The first statement does not compile because hat
is a variable, not a value, and both operands are automatically promoted to int
. When working with values, the compiler had enough information to determine the writer's intent. When working with variables, though, there is ambiguity about how to proceed, so the compiler reports an error. The second expression does not compile because 700
triggers an overflow for byte
, which has a maximum value of 127
.
Compound Assignment Operators
Besides the simple assignment operator (=
), Java supports numerous compound assignment operators. For the exam, you should be familiar with the compound operators in Table 2.6.
TABLE 2.6 Compound assignment operators
Operator | Example | Description |
---|---|---|
Addition assignment |
a += 5
|
Adds the value on the right to the variable on the left and assigns the sum to the variable |
Subtraction assignment |