Because the cast is automatic, nothing warns you when the result does not fit. Java narrows by discarding digits, and it does so without any complaint at all.
public class Truncation {
public static void main(String[] args) {
byte c = 1;
c *= 300;
// 1 * 300 = 300, which does not fit in a byte
System.out.println("byte c = 1; c *= 300; -> c = " + c);
int i = 1;
i += 2.7;
// 1 + 2.7 = 3.7, truncated to 3
System.out.println("int i = 1; i += 2.7; -> i = " + i);
int x = 5;
x /= 2.0;
// a double on the right, an int on the left
System.out.println("int x = 5; x /= 2.0; -> x = " + x);
short s = 32767;
s += 1;
// overflow wraps silently
System.out.println("short 32767 + 1 -> s = " + s);
int big = Integer.MAX_VALUE;
big += 1;
System.out.println("Integer.MAX_VALUE + 1 -> " + big);
}
}
The real output:
byte c = 1;
c *= 300;
-> c = 44 int i = 1;
i += 2.7;
-> i = 3 int x = 5;
x /= 2.0;
-> x = 2 short 32767 + 1 -> s = -32768 Integer.MAX_VALUE + 1 -> -2147483648
Line by line, these are the rules:
i += 2.7 promotes to double, adds to get 3.7, then casts back to int and truncates towards zero, giving 3. The .7 is simply discarded.
If silent truncation is a real risk, use Math.toIntExact or do the arithmetic in a wider type on purpose:
long count = 5_000_000_000L;
// 5 billion, far past the int range
int silently =(int) count;
// legal cast, silently gives 705032704
System.out.println("(int) count = " + silently);
// a wrong number, no warning
int safe = Math.toIntExact(count);
// throws ArithmeticException
(int) count = 705032704 Math.toIntExact throws: ArithmeticException
The same idea exists for long in Math.addExact and Math.multiplyExact, and both are worth reaching for whenever a number comes from outside your program.