Java
Integer
Autoboxing
== operator
Integer Cache

Why do comparisons with Integer.valueOfString give different results for 127 and 128?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Java, comparing objects and primitive types can sometimes yield unexpected results, especially when dealing with numerical data. A common point of confusion arises when comparing Integer objects using the == operator after using Integer.valueOf(String) to convert strings to integers. This behavior is particularly noticeable with the numbers 127 and 128, and it can lead to puzzling bugs if not understood properly.

The Basics of Integer Pooling

Java's Integer class is part of the larger pool of classes that wrap primitive types into objects, known as wrapper classes. An essential optimization used by Java for such classes is "integer pooling." By default, Java caches Integer objects in a fixed range to optimize memory usage and increase access speed. The precise knowledge of this caching mechanism is key to understanding the observed behavior when using ==.

Integer Caching in Java

When Java converts a string to an integer using Integer.valueOf(String), it internally calls Integer.valueOf(int). This method may retrieve a cached instance of an Integer object rather than creating a new one. Specifically, Java automatically caches Integer objects that represent int values from -128 to 127.

Here's a crucial point: Integer caching by default affects only values within this range (-128 to 127). Therefore, the comparison behavior changes once numbers fall outside this range.

Behavioral Comparisons

Case 1: Integer 127

When using Integer.valueOf(String) for the string "127":

java
1Integer a = Integer.valueOf("127");
2Integer b = Integer.valueOf("127");
3
4if (a == b) {
5    System.out.println("a and b are the same instance.");
6} else {
7    System.out.println("a and b are different instances.");
8}

The output will be:

 
a and b are the same instance.

In this case, both a and b reference the same cached Integer instance for the value 127, resulting in a true result when using ==.

Case 2: Integer 128

Now, consider a similar comparison for the string "128":

java
1Integer x = Integer.valueOf("128");
2Integer y = Integer.valueOf("128");
3
4if (x == y) {
5    System.out.println("x and y are the same instance.");
6} else {
7    System.out.println("x and y are different instances.");
8}

The output will be:

 
x and y are different instances.

Here, x and y are not the same because the value 128 is outside the default caching range, so Integer.valueOf(String) creates new distinct instances for each call.

Key Points

Let's summarize the differences:

PropertyValue 127Value 128
CachingYesNo
Result of ==TrueFalse
Same InstanceYes (from cache)No (created anew)
Constructor BehaviorUses cached instanceCreates new instance

Understanding Integer Caching

Java's integer caching mechanism can be adjusted using a system property during runtime: -Djava.lang.Integer.IntegerCache.high=<value>. This property allows configuring the upper bound of the cached values. This optimization decides whether an Integer uses a cached instance or a newly created one.

Best Practices

  1. Use .equals(): For comparing Integer objects, always use the .equals() method to compare actual values, irrespective of caching behavior.
java
   if (x.equals(y)) {
       System.out.println("x and y are equal in value.");
   }
  1. Avoid == for Objects: Use == primarily for comparing primitive types and object identities when that's your specific intention.

Additional Details

Performance Benefits

Caching is especially beneficial for avoiding unnecessary allocations and improving performance for repeatedly used numbers. The choice of -128 to 127 as the default range comes from its frequent usage in numerous common applications such as loop indices, counters, etc.

Customizing Cache Size

Programmatically deciding the extent of caching can be beneficial if dealing with a specific application domain where numbers outside the default caching bounds are frequently used.

Conclusion

Understanding Java's integer caching mechanism is crucial for correctly managing memory and achieving predictable results when working with integer comparisons. While the default behavior optimizes performance and memory usage, being aware of these concepts helps avoid subtle bugs, especially when comparing Integer objects using the == operator.

This nuanced understanding also encourages programmers to adhere to best practices, like consistently using .equals() for object comparisons, ensuring robustness regardless of underlying optimizations.


Course illustration
Course illustration

All Rights Reserved.