Читать книгу OCP Oracle Certified Professional Java SE 17 Developer Study Guide - Jeanne Boyarsky - Страница 149
Real World Scenaria 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 (+
).