Integer cache trap in Java
Integer.valueOf caches -128..127 so == on boxed values is unreliable.
== says true. Two Integers holding 128: == says false. Same code, one number apart. Is Java broken?== on objects compares addresses
For objects, == asks "are these the same object?", not "do they hold the same value?". Two separate Integer objects that both hold 1000 are not ==.
The cache
Integer.valueOf, which autoboxing uses, keeps ready-made objects for −128 to 127, the range of a byte. Box 100 twice and you get the same cached object. Box 1000 twice and you usually get two new objects.
Your turn
What does this print?
Integer a = 100, b = 100;
Integer c = 200, d = 200;
System.out.println(a == b);
System.out.println(c == d);true truetrue falsefalse false
Show the answer
100 is inside the cache, so a and b are the same object: true. 200 is outside, so c and d are two different objects: false.
Mixed with an int?
Integer a = 1000; int b = 1000; Is a == b true or false?
Think about it, then reveal the answer
true. When one side of == is a primitive int, the Integer is unboxed and the values are compared. The cache only matters when both sides are objects.
Works in tests, fails in production
Tests often use small numbers like 1, 2 or 42. Those are inside the cache, so == seems to work. Real IDs and amounts are bigger, and == suddenly fails. The cache's upper bound can even be raised with a JVM flag, so never rely on it.
Comparing boxed values
if (x == y) { ... }Compares references, so it's unreliable outside −128..127.
if (Objects.equals(x, y)) { ... }Compares values and is null-safe. x.equals(y) or x.intValue() would throw NullPointerException if x is null.
In real projects
Comparing two Long user IDs with == passes every test with user 7, then fails for user 1,000,000 in production. It's a classic interview question, and static analysis tools like SpotBugs flag == on boxed numbers.
Key takeaways
- Cached range by default: −128 to 127
- == on two Integers compares references
- Use equals() or Objects.equals() for values
- Integer == int unboxes and compares values
The cache's upper limit can be raised with the JVM option -XX:AutoBoxCacheMax=1000. The lower limit stays fixed at −128.
Practice questions
Which range does Integer.valueOf cache by default?
- 0 to 255
- −128 to 127
- −127 to 128
- 0 to 1000
Check your answer
−128 to 127. The cache covers −128..127, the range of a byte. (The upper bound can be raised with a JVM flag, which is another reason not to rely on it.)
What does this print?
Integer a = 127, b = 127;
Integer c = 128, d = 128;
System.out.println(a == b);
System.out.println(c == d);- true true
- false false
- true false
- false true
Check your answer
true false. 127 is in the cache, so a and b refer to the same object. 128 isn't, so c and d are two separate objects and == is false.