Friday, October 1, 2010

Why Comparing Integer using == in Java 5 is Bad?

Java 5 introduced auto-boxing which automatically converts int to Integer and because of that many Java developers started writing code for comparing int variable to Integer object and Integer to Integer using == operator. You should avoid that because it can create subtle bugs in your program because it only works for a particular range of integers and not for all. There is another problem as well, when you compare int variable to Integer object using == operator, the Integer object is converted to primitive value. This can throw null pointer exception if the Integer object is null, which can crash your program. Now when you compare two Integer object using == operator, Java doesn't compare them by value, but it does reference comparison. When means even if the two integer has same value, == can return false because they are two different object in heap. That's why you should use equals() method to compare objects. There is one more point which makes thing tricky, caching of integer objects by Integer.valueOf() method. What this mean is that your program will work for some input but not for others. This happens because auto boxing uses Integer.valueOf() method to convert Integer to int and since method caches Integer object for range -128 to 127, it return same Integer object in heap, and that's why == operator return true if you compare two Integer object in the range -128 to 127, but return false afterwards, causing bug. Before Java 1.4 that was not a problem because there was no autoboxing, so you always knew that == will check reference in heap instead of value comparison.


Comparing Integer object with == in Java

Why you should not compare Integer using == in Java 5Some of the JVM cache objects of some wrapper class e.g. Integer from -128 to 127 and return same object which if compare via “ ==” can return true but after this range this validity doesn't work and to make it worse this behavior is JVM dependent so better avoid this kind of check and use equals() method. e.g.

Integer i1 = 260;
Integer i2 = 260;

if (i1 == i2) {
    System.out.println("i1 and i2 is equal");
} else {
   System.out.println("i1 and i2 is not equal ");
}

Here you will most probably get "i1 and i2 is not equal " at least in my machine.
because in this case, unboxing operation is not involved. The literal 260 is boxed into two different Integer objects ( again it varies between JVM to JVM) , and then those objects are compared with ==. The result is false, as the two objects are different instances, with different memory addresses. Because both sides of the == expression contain objects, no unboxing occurs.

Integer i1 = 100;
Integer i2 = 100;

if (i1 == i2) {
    System.out.println("i1 and i2 is equal");
} else {
   System.out.println("i1 and i2 is not equal ");
}


Here, most probably you will get the text "i1 and i2 is equal".
Because int values from -127 to 127 are in a range which most JVM will like to cache so the VM actually uses the same object instance (and therefore memory address) for both i1 and i2. As a result, == returns a true result.

This is very indeterministic and only shown by example since some JVM do optimization at certain integer value and try to return same object every time but its not guaranteed or written behavior.

So best is to avoid this kind of code in post Java 1.5 and instead use equals() method to compare Integers in Java, which is more deterministic and correct.

7 comments :

Anonymous said...

In order to avoid surprise, I think it's better to always think of "==" in term of "same object" instead of "equals"

Anonymous said...

Yet another reason why I think this language is a dead end - the people responsible for the language design are simply nuts. It's rather unwise to make certain elements of the language behave differently depending on the level of optimization.

veggen said...

It doesn't really have anything to do with "recommended practice". That is the very definition of "==" and "equals".

Glamdring said...

@Anonymous (2nd) you are wrong. The practice is to never use `==` for objects. It's used only for primitives. So no confusion there.

Anonymous said...

I never use autoboxing. I use Integer.valueOf instead, so it is clear, that I am working with objects. You can configure eclipse to mark autoboxing as error.

Btw. You can configure the cache-max-value by the VM-Param -XX:AutoBoxCacheMax=X. The value 127 is default.

Javin @ FIX Protocol Tutorials said...

Hi Anonymous thanks for sharing VM-Param -XX:AutoBoxCacheMax=X to us. I think valueOf is also work on same principle and return same object until a limit most likely in the range of byte -127 to 128 and return different object outside the range.

Javin @ FIX Protocol Tutorials said...

@Glamdring , thanks for answering @Anonymous (2nd) and making it clear not to use `==` for objects.

Post a Comment