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":
The output will be:
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":
The output will be:
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:
| Property | Value 127 | Value 128 |
| Caching | Yes | No |
Result of == | True | False |
| Same Instance | Yes (from cache) | No (created anew) |
| Constructor Behavior | Uses cached instance | Creates 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
- Use
.equals(): For comparingIntegerobjects, always use the.equals()method to compare actual values, irrespective of caching behavior.
- 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.

