📦 Variables & Types · Beginner

Integer cache trap in Java

Integer.valueOf caches -128..127 so == on boxed values is unreliable.

🧩 The mysteryTwo Integers holding 127: == 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.

🔮 Predict it

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);
  1. true true
  2. true false
  3. false 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.

🤔 Think first

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.

⚠️ The trap

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

✗ Broken
if (x == y) { ... }

Compares references, so it's unreliable outside −128..127.

✓ Correct
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 the real world

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

  1. Cached range by default: −128 to 127
  2. == on two Integers compares references
  3. Use equals() or Objects.equals() for values
  4. Integer == int unboxes and compares values
🤯 Did you know?

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?

  1. 0 to 255
  2. −128 to 127
  3. −127 to 128
  4. 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);
  1. true true
  2. false false
  3. true false
  4. 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.

Next: fields start at 0, false or null, but local variables start at... nothing. Why the double standard?