• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

using == with Integer

 
Ramya Subraamanian
Ranch Hand
Posts: 178
17
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
this snippet below gives me true with ==



and false here



I understand that == operator returns true if the primitives values are identical. and with 2 references they return true if they point to the same object. == when used on wrapper, will be unboxed to primitve and compares as though they were 2 primitives...but why then it gives false in 2nd case.

while we can compare other wrapper types with ==. why does == give me false on Float and Double.



 
Roel De Nijs
Sheriff
Posts: 10662
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ramya Subraamanian wrote:I understand that == operator returns true if the primitives values are identical. and with 2 references they return true if they point to the same object.

Spot-on!

Ramya Subraamanian wrote:== when used on wrapper, will be unboxed to primitve and compares as though they were 2 primitives...

That's incorrect! A wrapper class instance will only be unboxed when the other operand is a primitive value. In your examples both operands are references to wrapper class instances, so the == operator will compare references, not primitive values (there's no unboxing happening here).

Ramya Subraamanian wrote:but why then it gives false in 2nd case.

Carefully read this excellent thread about using the == operator on wrapper classes. It explains everything you need to know with a bunch of illustrative code snippets.

Hope it helps!
Kind regards,
Roel
 
Winston Gutkowski
Bartender
Pie
Posts: 10571
64
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:
Ramya Subraamanian wrote:== when used on wrapper, will be unboxed to primitve and compares as though they were 2 primitives...
That's incorrect!...

I agree with you that it's a fact; but to me the question is: should it be?

It seems to me to go against the "ethos" of autoboxing, which is to treat Integer and int as equivalent where possible. And since checking whether two Integers are the same object is basically a useless test, it strikes me that they could have made this an exception to the general rule of reference type equality.

However, @Ramya: it's probably too late to change now, so you just have to live with it.
But I'm with you in spirit.

Nice question.

Winston
 
Scott Selikoff
author
Saloon Keeper
Posts: 4031
18
Eclipse IDE Flex Google Web Toolkit
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Auto-boxing and auto-unboxing are useful, but you don't always need to rely on them. In the first example, you can call floatValue() or doubleValue() to compare the contents of the objects, instead of the objects themselves. Likewise, when you auto-unbox a wrapper class, you have to make sure the object isn't null.

If I'm working with all wrapper classes, I tend to explicitly call the "to primitive" method like intValue() although that might be a facet of learning to write Java before auto-boxing and auto-unboxing existed. In other words, I use them for convenience when comparing two different types (primitive and wrapper) but disregard them when I'm working entirely with primitives, or entirely with wrapper objects.

 
Paul Anilprem
Enthuware Software Support
Ranch Hand
Posts: 3817
10
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Scott Selikoff wrote:Auto-boxing and auto-unboxing are useful, but you don't always need to rely on them. In the first example, you can call floatValue() or doubleValue() to compare the contents of the objects, instead of the objects themselves.

or just use equals, which is the preferred approach for comparing content.
Comparing objects using == has always been a bad idea. Even Strings are created using an auto-boxing like syntax (String str = "something"; i.e. without using new), and it is never recommended to use == to compare two strings either, irrespective of interning.
 
Scott Selikoff
author
Saloon Keeper
Posts: 4031
18
Eclipse IDE Flex Google Web Toolkit
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's fine to use == if you know you are working with primitive values instead of objects. There's no performance improvement in using equals() vs converting to primitives. In fact, you may want to convert them for other reasons, such as calling intValue() on Double values (although Math.round() is often preferred).

That said, there are places where equals() and == differ on primitives. From the Javadoc on Double, for example:


Note that in most cases, for two instances of class Double, d1 and d2, the value of d1.equals(d2) is true if and only if

d1.doubleValue() == d2.doubleValue()
also has the value true. However, there are two exceptions:

* If d1 and d2 both represent Double.NaN, then the equals method returns true, even though Double.NaN==Double.NaN has the value false.
* If d1 represents +0.0 while d2 represents -0.0, or vice versa, the equal test has the value false, even though +0.0==-0.0 has the value true.
This definition allows hash tables to operate properly.


Depending on your desired behavior, you may want -0.0 to be the same as +0.0. In this case, == on the primitive values would be preferred.
 
Ramya Subraamanian
Ranch Hand
Posts: 178
17
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The discussion about == and .equals was insightful.
@ Roel - I went through the thread(and the threads inside them).It had overwhelming amount of information for my small brain.okay , Integer will return true only if it compares value between -128 and 127. when its above 127 , it creates a new address space.



gets created in cache and does not create a new address hence == returns true. and right there is no need to unbox because both p and q are wrappers.



Above it is > 127, its equivalent of creating a new address like below space hence == returns false.


my understanding with ==(correct me ..if something wrong)
1. when comparing primitive and wrapper . wrapper unboxes to primitive and compares to give result
2. comparing primitive and Number gives compiler error as it cannot Unbox Number.
3. comparing 2 different Wrapper types gives compilation error because they are incompatible types.
3. comparing Integer and Number compiles. Since Number is unboxed as Integer and comparison of 2 Integer instances returns true.
4. Comparing Short and Number compiles. but since Number is unboxed as Integer refers to cached Integer instance,Short is cached Short instance. they return false, even though contents are same.

Still unable to figure out why Float and Double return false with ==

Float f3 =125f -> this calls Float.valueOf() which returns a Float object .
and f3 of type Float

Double d11 = 10.0 is of Type Double.

but d11.doubleValue()==d22.doubleValue() and f3.floatValue()==f3.floatValue() returns true because they are converted to primitive double and float and compared.

for comparing 2 Float values in real life, we should use java.lang.Float.compare() and compareTo(which calls compare). In compare method the Float is converted to int bits and then compared using ==. Double uses Double.compare() where it converts Double to LongBits and then compares using ==.
 
Roel De Nijs
Sheriff
Posts: 10662
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 4
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ramya Subraamanian wrote:Integer will return true only if it compares value between -128 and 127.

That's not 100% accurate! The == operator will return true, not Integer. And of course only if both reference variables refer to the same object.

Ramya Subraamanian wrote:gets created in cache and does not create a new address hence == returns true. and right there is no need to unbox because both p and q are wrappers.

True! Just remember that instances are only cached if they are created using autoboxing and the value is between -128 and 127 (inclusive). If the value is created using the constructor, it's a different object and thus false will be returned as this code snippet illustrates

Ramya Subraamanian wrote:Above it is > 127, its equivalent of creating a new address like below space hence == returns false.

Spot-on!

Ramya Subraamanian wrote:1. when comparing primitive and wrapper . wrapper unboxes to primitive and compares to give result

Again not 100% accurate! It's true that the wrapper class instance is unboxed, but it's the == operator which compares and returns the result.

Ramya Subraamanian wrote:2. comparing primitive and Number gives compiler error as it cannot Unbox Number.

True!

Ramya Subraamanian wrote:3. comparing 2 different Wrapper types gives compilation error because they are incompatible types.

Indeed! And that makes sense, because two objects of different wrapper types can never be the same object.

Ramya Subraamanian wrote:3. comparing Integer and Number compiles. Since Number is unboxed as Integer and comparison of 2 Integer instances returns true.

That's incorrect! When you are comparing an Integer reference variable and a Number reference variable both having the same int primitive valuie, the == operator will return true because both reference variables refer to the same object and thus no unboxing is happening. Unboxing will only happen if one of the operands is a primitive value! And besides Number you could even use Object as reference type. Illustrated in this code snippet

Ramya Subraamanian wrote:4. Comparing Short and Number compiles. but since Number is unboxed as Integer refers to cached Integer instance,Short is cached Short instance. they return false, even though contents are same.

Again that's incorrect for the same reason! When you use the == operator on two reference variables, there is no unboxing! That's very important to remember. And the return value of the == operator also depends on which object the Number reference variable refers to. Here is another code snippet to prove this statement

Ramya Subraamanian wrote:Still unable to figure out why Float and Double return false with ==

Because Float and Double values are never cached. Don't forget these are floating-point values, so even if you would limit the range to cache these values to -1 and +1 the number of cached values would be infinite (0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001,... on are all values in range). That's why these values are never cached and thus the == operator will return false if you compare two Float (or Double) objects with the same primitive float (or double) value.

Hope it helps!
Kind regards,
Roel
 
Winston Gutkowski
Bartender
Pie
Posts: 10571
64
Eclipse IDE Hibernate Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ramya Subraamanian wrote:Integer will return true only if it compares value between -128 and 127.

Not true, but I don't plan on re-hashing Roel's excellent post.

It might be worth knowing a little of the history behind all this mess:
In the beginning there were primitives and wrapper classes, and never the twain met. And everything was simple in the Garden of Java.
But then some, who had eaten of the Tree of Knowledge, said: "Why can't these things, which have been separate, be made similar?"
"And why can't common values be cached?" said others.
"And why don't we tell everybody all about it?" said another forgetting, in his haste, one of the prime directives of the Garden of Java.
"But everything must be backward-compatible" said dinosaurs, who liked their simple garden.
And so it was made so.
And things, while maybe shorter, were no longer so simple...

Winston
 
Roel De Nijs
Sheriff
Posts: 10662
144
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Winston Gutkowski wrote:
Roel De Nijs wrote:
Ramya Subraamanian wrote:== when used on wrapper, will be unboxed to primitve and compares as though they were 2 primitives...
That's incorrect!...

I agree with you that it's a fact; but to me the question is: should it be?

In my opinion it definitely should be for several reasons.

(1) It keeps things simple and clean. With one (simple) sentence you can explain the rule (without having to add an "unless both are denoting wrapper class instances" clause): when both operands are reference variables, the == operator will return true if both refer to the same object.

(2) If try to compare incompatible types (e.g. Cat and Dog, Short and Integer,...) using the == operator, you'll get a compiler error. But if both (wrapper class) operands are unboxed, incompatible types (with the same primitive value) become equal

(3) Related to (1) and (2), operator overloading in Java is limited to a strict minimum (only the + operator) and I think that helps to keep a programming language simple and clean. If the behavior is different depending on the operand types, the == operator would be overloaded as well.

(4) What if you (for some weird/strange business requirement) you need to check if both reference variables refer to the same object. If it's always unboxed, you can't perform this check anymore. Now you have the choice: use reference variables for reference equality or use primitiveTypeValue() methods for primitive value equality.

So I think it was the correct decision to implement it the way they did!
 
Scott Selikoff
author
Saloon Keeper
Posts: 4031
18
Eclipse IDE Flex Google Web Toolkit
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Great list, Roel, especially #4.

When it comes down to it, the reason Java works the way it does is primarily backwards compatibility with previously compiled code. Aka.. Auto-boxing and auto-unboxing are compiler time enhancements only. Consider what would happen if you used an Object reference two Integer objects, compiled in Java 1.4?



Like using "new String", this code outputs false since two objects are created (see: 'new' keyword) and tested. It needs to output the same value in both Java 1.4 and 1.5 (when boxing was added) if it did not, *a lot* of existing code would be unusable every time you upgraded to the next version of Java!

If Java didn't have to worry about backwards compatibility it's possible they could have added a rule that made the above output to true, but Java is keen on not breaking previously compiled code. Also remember that auto-boxing and auto-unboxing were added in Java 1.5 when generics (another compiler time enhancement) was added. The goal in 1.5 was to add a lot of new syntax to Java without breaking any existing code from 1.4.
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic