Java: Integers may overflow, but bytes may not?
int expressions allowed to overflow, but not
int i = Integer.MAX_VALUE + 1; // allowed to overflow byte b = possible lossy conversion from int to byteByte.MAX_VALUE + 1; // not allowed to overflow
Before you shout "
Byte.MAX_VALUE + 1 is an
int expression! This is a simple type error!" note that this does compile:
byte b = Byte.MAX_VALUE + 0;
The + Operator
+ operator is indeed only defined for
String operands. In our snippet
Byte.MAX_VALUE will therefore be promoted to an
int and the result of the addition will be of type
byte plus a
byte is an
But as we saw earlier, there's something else at play here…
Something about that overflow…
The compile error only occurs when there's a byte overflow, which reveals that the computation is performed at compile time. The JLS refers to this as a compile-time constant expression:
15.28 Constant Expression
A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:
- Literals of primitive type and literals of type String (§3.10.5)
- The additive operators + and -
- Qualified names of the form TypeName.Identifier that refer to constant variables (§4.12.4) JLS §15.28
A constant variable is a variable that is final and initialized with a compile-time constant expression.
Byte.MAX_VALUE happens to be a constant variable. (If it wasn’t
byte b = Byte.MAX_VALUE + 0 would not have compiled!)
Example: Making a variable final makes it a constant expression.
Why is a byte not allowed to overflow like an int?
There are some special language rules for so called assignment contexts. Constant expressions that fit in the type of the variable (
byte in our case) will be automatically converted by the compiler.
5.2. Assignment Context
A narrowing primitive conversion may be used if the type of the variable is byte, short, or char, and the value of the constant expression is representable in the type of the variable. JLS §5.2
So here’s the actual reason the snippet at the top doesn’t compile: Constant expressions that do not fit does not get converted, and thus the expression remains as an
int and a typing error occurs since an
int cannot be stored in a
An even funnier case
During evaluation of constant expressions, the compiler follows the rules of 2’s complement 2 arithmetic. This means that an
int expression can overflow and wrap back into the range of a
byte a = Integer.MAX_VALUE; // Does not compile. byte b = Integer.MAX_VALUE * 2; // Does compile!
b variable will contain the value −2.
There are literals for all primitive types (
short. No byte or short literals? discusses this oddity.