Tuesday, July 20, 2021

Why Avoid Comparing Integers in Java using == Operator? Example

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 the int variable to the Integer object using == operator, the Integer object is converted to a primitive value. This can throw a null pointer exception if the Integer object is null, which can crash your program.

Now when you compare two Integer objects using a == operator, Java doesn't compare them by value, but it does reference comparison. When means even if the two integers have the same value, == can return false because they are two different objects in the heap. That's why you should use the equals() method to compare objects.

There is one more point that makes things tricky, caching of integer objects by Integer.valueOf() method. What this means is that your program will work for some input but not for others.

This happens because autoboxing uses Integer.valueOf() method to convert Integer to int and since method caches Integer object for range -128 to 127, it returns 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 afterward, causing a bug.

Before Java 1.4 that was not a problem because there was no autoboxing, so you always knew that == will check the reference in heap instead of value comparison.

And, If you are new to the Java world then I also recommend you go through these Java Programming Courses to learn Java in a better and more structured way. This is one of the best and up-to-date courses to learn Java online.




Avoid 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 the 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. like

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, the unboxing operation is not involved. The literal 260 is boxed into two different Integer objects ( again it varies between JVM to JVM), and when 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 are 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 values and try to return the same object every time but it's not guaranteed or written behavior.

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

Further Learning
Free Java Programming Courses

13 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.

kaqqao 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.

dakshit said...

very helpfull

javin paul said...

Hello Dakshit, glad you find information useful.

Joseph McCay said...

I found myself asking the question what is the purpose of this article. == compares the actual object & not it's state

Unknown said...

thanks it is very helpful to me

Anonymous said...

It's seem that it when comparing two integer value using .equals .....it take it as string so,that both integer will be compared with no limitation and give out correct output but as String ... :)

javin paul said...

I think equal will take Integer object if you want to compare Integer value.

Post a Comment