Why Do == Comparisons with Integer.Valueof(String) Give Different Results for 127 and 128

Why do == comparisons with Integer.valueOf(String) give different results for 127 and 128?

There's a striking difference here.

valueOf is returning an Integer object, which may have its values cached between -128 and 127. This is why the first value returns true - it's cached - and the second value returns false - 128 isn't a cached value, so you're getting two separate Integer instances.

It is important to note that you are comparing references with Integer#valueOf, and if you are comparing a value that is larger than what the cache supports, it will not evaluate to true, even if the parsed values are equivalent (case in point: Integer.valueOf(128) == Integer.valueOf(128)). You must use equals() instead.

parseInt is returning a primitive int. This is why the third value returns true - 128 == 128 is evaluated, and is of course, true.

Now, a fair bit happens to make that third result true:

  • An unboxing conversion occurs with respect to the equivalence operator you're using and the datatypes you have - namely, int and Integer. You're getting an Integer from valueOf on the right hand side, of course.

  • After the conversion, you're comparing two primitive int values. Comparison happens just as you would expect it to with respect to primitives, so you wind up comparing 128 and 128.

Why is 128==128 false but 127==127 is true when comparing Integer wrappers in Java?

When you compile a number literal in Java and assign it to a Integer (capital I) the compiler emits:

Integer b2 =Integer.valueOf(127)

This line of code is also generated when you use autoboxing.

valueOf is implemented such that certain numbers are "pooled", and it returns the same instance for values smaller than 128.

From the java 1.6 source code, line 621:

public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}

The value of high can be configured to another value, with the system property.

-Djava.lang.Integer.IntegerCache.high=999

If you run your program with that system property, it will output true!

The obvious conclusion: never rely on two references being identical, always compare them with .equals() method.

So b2.equals(b3) will print true for all logically equal values of b2,b3.

Note that Integer cache is not there for performance reasons, but rather to conform to the JLS, section 5.1.7; object identity must be given for values -128 to 127 inclusive.

Integer#valueOf(int) also documents this behavior:

this method is likely to yield significantly better space and time performance by caching frequently requested values. This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.

Why Integer class caching values in the range -128 to 127?

Just wondering, why between -128 and 127?

A larger range of integers may be cached, but at least those between -128 and 127 must be cached because it is mandated by the Java Language Specification (emphasis mine):

If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

The rationale for this requirement is explained in the same paragraph:

Ideally, boxing a given primitive value p, would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rules above are a pragmatic compromise. The final clause above requires that certain common values always be boxed into indistinguishable objects. [...]

This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K.


How can I cache other values outside of this range.?

You can use the -XX:AutoBoxCacheMax JVM option, which is not really documented in the list of available Hotspot JVM Options. However it is mentioned in the comments inside the Integer class around line 590:

The size of the cache may be controlled by the -XX:AutoBoxCacheMax=<size> option.

Note that this is implementation specific and may or may not be available on other JVMs.

Why equal operator works for Integer value until 128 number?

Check out the source code of Integer . You can see the caching of values there.

The caching happens only if you use Integer.valueOf(int), not if you use new Integer(int). The autoboxing used by you uses Integer.valueOf.

According to the JLS, you can always count on the fact that for values between -128 and 127, you get the identical Integer objects after autoboxing, and on some implementations you might get identical objects even for higher values.

Actually in Java 7 (and I think in newer versions of Java 6), the implementation of the IntegerCache class has changed, and the upper bound is no longer hardcoded, but it is configurable via the property "java.lang.Integer.IntegerCache.high", so if you run your program with the VM parameter -Djava.lang.Integer.IntegerCache.high=1000, you get "Same values" for all values.

But the JLS still guarantees it only until 127:

Ideally, boxing a given primitive value p, would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rules above are a pragmatic compromise. The final clause above requires that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly.

For other values, this formulation disallows any assumptions about the identity of the boxed values on the programmer's part. This would allow (but not require) sharing of some or all of these references.

This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all characters and shorts, as well as integers and longs in the range of -32K - +32K.

Comparing boxed Long values 127 and 128

TL;DR

Java caches boxed Integer instances from -128 to 127. Since you are using == to compare objects references instead of values, only cached objects will match. Either work with long unboxed primitive values or use .equals() to compare your Long objects.

Long (pun intended) version

Why there is problem in comparing Long variable with value greater than 127? If the data type of above variable is primitive (long) then code work for all values.

Java caches Integer objects instances from the range -128 to 127. That said:

  • If you set to N Long variables the value 127 (cached), the same object instance will be pointed by all references. (N variables, 1 instance)
  • If you set to N Long variables the value 128 (not cached), you will have an object instance pointed by every reference. (N variables, N instances)

That's why this:

Long val1 = 127L;
Long val2 = 127L;

System.out.println(val1 == val2);

Long val3 = 128L;
Long val4 = 128L;

System.out.println(val3 == val4);

Outputs this:

true

false

For the 127L value, since both references (val1 and val2) point to the same object instance in memory (cached), it returns true.

On the other hand, for the 128 value, since there is no instance for it cached in memory, a new one is created for any new assignments for boxed values, resulting in two different instances (pointed by val3 and val4) and returning false on the comparison between them.

That happens solely because you are comparing two Long object references, not long primitive values, with the == operator. If it wasn't for this Cache mechanism, these comparisons would always fail, so the real problem here is comparing boxed values with == operator.

Changing these variables to primitive long types will prevent this from happening, but in case you need to keep your code using Long objects, you can safely make these comparisons with the following approaches:

System.out.println(val3.equals(val4));                     // true
System.out.println(val3.longValue() == val4.longValue()); // true
System.out.println((long)val3 == (long)val4); // true

(Proper null checking is necessary, even for castings)

IMO, it's always a good idea to stick with .equals() methods when dealing with Object comparisons.

Reference links:

  • https://today.java.net/pub/a/today/2005/03/24/autoboxing.html
  • https://blogs.oracle.com/darcy/entry/boxing_and_caches_integer_valueof
  • http://java.dzone.com/articles/surprising-results-autoboxing

Why does the behavior of the Integer constant pool change at 127?

No, the constant pool for numbers doesn't work the same way as for strings. For strings, only compile-time constants are interned - whereas for the wrapper types for integer types, any boxing operation will always use the pool if it's applicable for that value. So for example:

int x = 10;
int y = x + 1;
Integer z = y; // Not a compile-time constant!
Integer constant = 11;
System.out.println(z == constant); // true; reference comparison

The JLS guarantees a small range of pooled values, but implementations can use a wider range if they wish.

Note that although it's not guaranteed, every implementation I've looked at uses Integer.valueOf to perform boxing operations - so you can get the same effect without the language's help:

Integer x = Integer.valueOf(100);
Integer y = Integer.valueOf(100);
System.out.println(x == y); // true

From section 5.1.7 of the JLS:

If the value p being boxed is true, false, a byte, or a char in the range \u0000 to \u007f, or an int or short number between -128 and 127 (inclusive), then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.

Ideally, boxing a given primitive value p, would always yield an identical reference. In practice, this may not be feasible using existing implementation techniques. The rules above are a pragmatic compromise. The final clause above requires that certain common values always be boxed into indistinguishable objects. The implementation may cache these, lazily or eagerly. For other values, this formulation disallows any assumptions about the identity of the boxed values on the programmer's part. This would allow (but not require) sharing of some or all of these references.

This ensures that in most common cases, the behavior will be the desired one, without imposing an undue performance penalty, especially on small devices. Less memory-limited implementations might, for example, cache all char and short values, as well as int and long values in the range of -32K to +32K.

Different between parseInt() and valueOf() in java?

Well, the API for Integer.valueOf(String) does indeed say that the String is interpreted exactly as if it were given to Integer.parseInt(String). However, valueOf(String) returns a new Integer() object whereas parseInt(String) returns a primitive int.

If you want to enjoy the potential caching benefits of Integer.valueOf(int), you could also use this eyesore:

Integer k = Integer.valueOf(Integer.parseInt("123"))

Now, if what you want is the object and not the primitive, then using valueOf(String) may be more attractive than making a new object out of parseInt(String) because the former is consistently present across Integer, Long, Double, etc.

Clarification regarding Integer comparison?

It is because Integer caching.

From java language specification 5.1.7

If the value p being boxed is true, false, a byte, or a char in the range 
\u0000 to \u007f, or an int or short number between -128 and 127 (inclusive),
then let r1 and r2 be the results of any two boxing conversions of p.
It is always the case that r1 == r2.

Ideally, boxing a given primitive value p, would always yield an identical reference.

Integer i = Integer.valueOf(127);  
Integer j = Integer.valueOf(127);

Both i and j point to same object. As the value is less than 127.

Integer k = Integer.valueOf(128);  
Integer l = Integer.valueOf(128);

Both k & l point to different objects. As the value is greater than 127.

As, you are checking the object references using == operator, you are getting different results.


Update

You can use equals() method to get the same result

System.out.println(i.equals(j));//equals() compares the values of objects not references  
System.out.println(k.equals(l));//equals() compares the values of objects not references

Output is

true
true
  1. == operator checks the actual object references.
  2. equals() checks the values(contents) of objects.

Answer to comment

You have,

Integer i = Integer.valueOf(127); 

Here new object is created & reference is assigned to i

Integer j = Integer.valueOf(127); //will not create new object as it already exists 

Due to integer caching (number between -128 to 127) previously created object reference is assigned to j, then i and j point to same objects.

Now consider,

Integer p = Integer.valueOf(127); //create new object 
Integer q = Integer.valueOf(126); //this also creates new object as it does not exists

Obviously both checks using == operator and equals() method will result false. As both are different references and have different vales.

Integer Comparison Results Vary in Java

The answer to this question lies within the understanding of Autoboxing specified by Java programming language.

The variation in results of a == b happens because any integer between -128 to 127 are cached by the Integer class. When an int within this range is created it is retrieved from IntegerCache rather than creating a new Integer object.

Is this a bug? Of course not!

The Java class Integer is also called wrapper class because it provides an object that wraps an int primitive data type. In Java, comparing two value object is not straight forward. We should override the Object.equal method (and also the Object.hashCode) and use it to determine when two objects are equal. Using the == operator, in this case, we’re comparing the two physical object addresses. Java requires the new operator to create objects, which will be all stored on the JVM’s Heap. Local variables are stored on the JVM’s Stack, but they hold a reference to the object, not the object itself.

In first case when we check if a == b, we’re actually checking if both the references are pointing at the same location. Answer to this is NO!

But what happens when a & b are 50? To answer this we should have a look at the below Integer.valueOf method.

public static Integer valueOf(int i) {
if(i >= -128 && i <= IntegerCache.high)
return IntegerCache.cache[i + 128];
else
return new Integer(i);
}

We are using the Autoboxing Java function through this Integer.valueOf method to compare a == b. With the aim of optimizing the resources use, the Integer class maintains a cache memory of Integer instances. This way, all the new Integer requests with a value between -128 and IntegerCache.high (configurable) will return an identical object allocated once. So, when we ask if a == b, we get true because, behind the scene, a and b are pointing to the same memory location.

Now another question arises: Does this approach involve in instance sharing problems? The answer fortunately is no, because Integer was defined as an immutable object and that means if you want to modify it, you have to get a new instance… exciting, isn’t it?

Shishir

Why == for Integer.valueOf(500) returns false but true for 5?

There's cached instances of low numbered Integer objects but not any of higher valued Integer objects.

If you didn't notice before, you are comparing objects, not ints.



Related Topics



Leave a reply



Submit