Traps

87. The Integer Cache Trap

Integer.valueOf(n) caches instances for n in [-128, 127] โ€” so == returns true in that range but false outside it; always use .equals() to compare Integer objects.

Java 21 (core language)

Explanation

Integer.valueOf(int) is specified to cache Integer instances for values in the range -128 to 127 (inclusive). This means multiple calls with the same value in that range return the same object. Autoboxing uses Integer.valueOf(), so autoboxed integers in that range also share instances.

The trap: Integer a = 127; Integer b = 127; a == b is true (same cached object). Integer a = 128; Integer b = 128; a == b is false (different objects, cache exhausted). This inconsistency is a notorious interview question and a real bug source.

The fix: always use .equals() to compare Integer, Long, Double, and other wrapper objects. Never use == for reference type comparison unless you explicitly want identity equality. The JVM can extend the cache range with -XX:AutoBoxCacheMax=<N>, making the boundary non-portable.

Example

public class IntegerCacheTrap {
    public static void main(String[] args) {
        // In cache range (-128 to 127): == returns true
        Integer a = 100;
        Integer b = 100;
        System.out.println("100 == 100:   " + (a == b));       // true (cached)
        System.out.println("100 eq 100:   " + a.equals(b));    // true

        // Outside cache range: == returns false
        Integer c = 200;
        Integer d = 200;
        System.out.println("200 == 200:   " + (c == d));       // false! (not cached)
        System.out.println("200 eq 200:   " + c.equals(d));    // true (always correct)

        // Boundary: 127 is last cached, 128 is first uncached
        Integer e = 127; Integer f = 127;
        Integer g = 128; Integer h = 128;
        System.out.println("127 same obj: " + (e == f));       // true
        System.out.println("128 same obj: " + (g == h));       // false

        // Explicit valueOf: same caching behaviour as autoboxing
        Integer i = Integer.valueOf(127);
        Integer j = Integer.valueOf(127);
        System.out.println("valueOf(127): " + (i == j));       // true

        // Other wrapper caches:
        // Boolean: TRUE and FALSE are always the same instances
        Boolean bt = Boolean.valueOf(true);
        Boolean bf = Boolean.valueOf(true);
        System.out.println("Boolean == :  " + (bt == bf));     // true

        // Character: caches 0-127
        Character ca = 'A'; // 65, in cache
        Character cb = 'A';
        System.out.println("'A' == 'A':   " + (ca == cb));     // true

        // Rule: ALWAYS use .equals() for wrapper types!
        System.out.println("\nSafe comparison: always .equals()");
        System.out.println(c.equals(d)); // true โ€” reliable
    }
}

Sources