

Boxing with Java - powatom
http://www.tomhalligan.co.uk/category/technology/programming/

======
edwinnathaniel
This is because Java cache the Integer objects from -128 to 127.

So while it is correct that you should probably be more careful when dealing
with Autoboxing (or don't use it at all if you can...), there's one more layer
deep that the article did not touch: the actual implementation of Java.

<http://www.docjar.com/html/api/java/lang/Integer.java.html>

Observe the IntegerCache inner class in particular:

"Cache to support the object identity semantics of autoboxing for values
between -128 and 127 (inclusive) as required by JLS.

The cache is initialized on first usage. The size of the cache may be
controlled by the -XX:AutoBoxCacheMax=<size> option."

~~~
eropple
IIRC, this cache only works if you use Integer.valueOf instead of the
constructor. (I could be misremembering, but the reason for that seems obvious
to me.)

~~~
masklinn
> the reason for that seems obvious to me.

That Java's semantics force new object creation on constructor call, it's not
possible to do otherwise (as opposed to, say, JavaScript, Python or Ruby in
which object creation can be overridden and the "constructor" work like a
factory methods, when it isn't one outright) (which it is in Python and Ruby)

~~~
eropple
Yes, exactly.

------
mkaufmann
While one problem the blog post describes is valid, I think the authors comes
to the wrong conclusion. The problem is that the method is implemented in such
a way that it uses Integer objects which are different from the native integer
types.

Objects have very clear semantics concerning the == operator. It checks
whether the object identity is the same (alas it is the same object). There is
nothing special about it, thats also the reason why you can't compare two
strings with == and this is s.th. I think every Java developer learns within
the first days/weeks (often by first doing it wrong, I don't claim that this
is intuitive).

So in this light the correct solution, which the author even does not mention
anymore in the end, would be for the method to use the a.equals(b). Everything
would work. The point of the author that a team should agree on using either
one or the other is nonesene, because in some situations there is no choice
(e.g. HashMaps only work with objects). Also there is no real problem, because
whoever implemented the method know what he gets and should have implemented
it using the equals method. So in reality this should not be fixed with
creating seperate Integer instances but with fixing the method itself.

As a last comment, there is one pitfall to watch out for with autoboxing. When
you use the "int" type in your code and call a method which returns an
"Integer" and you compare with == you can get wrong results. I think of this
as a real problem, because often you know that a method will return a number
but you don't expect it to be returned as Integer. Or even worse between
versions of the api the method is changed from returning int to Integer and
you don't even notice because it compiles. But I think this happens very
rarely and personally I always return numbers as native types.

PS: But I can understand that it is sometimes confusing that the code is
working in some cases and not working in others, when it should never work! If
you want to get a really good understanding of the semantics of the Java
language I would advise to read ( <http://java.sun.com/docs/books/effective/>
)

~~~
powatom
The author ( me :P ) mentions that using a.equals(b) is the correct solution
right at the beginning of the post. Unfortunately this problem will continue
to occur as long as autoboxing exists, so I think it's a valid idea to simply
enforce a rule across your team that says 'Here's how we're going to avoid
autoboxing problems'. I intended this post to be more of an illustration of
what autoboxing does.

With regards to your comment that the solution is not to create separate
integer instances - I was attempting to show that this is a possible solution
to autoboxing headaches rather than 'the correct' solution for testing integer
equality, because the objects are not cached. Sometimes you want to use == for
valid reasons, the problem I had was because I wasn't vigilant enough in
checking my own code and used == when I shouldn't have used it in the first
place.

Perhaps this post could have been written more clearly - but as it happens,
you're spot on. The examples at the end of the post were intended to be
potential solutions to autoboxing headaches in general, rather than a solution
for my specific problem :)

~~~
mkaufmann
Ok, in that regard I think your post was very informative. Raising awareness
of this language detail is very important, because it can lead to bugs which
are very hard to detect.

The two most valuable advices from your post is directly the first line (but I
have to admit that I overread it the first time I looked at the post). And
second to use some tooling like the Eclipse code checker or findbugs (which
was mentioned in another comment) to make implicit conversions visible to the
programmer.

The only point I still disagree, though this is only a minor point, is that
even with your explanation the possible solution of creating seperate
instances is really no help. My point beeing that either you know that
autoboxing occurs at a point and one can handle it correctly, or one doesn't
know and in that case you also can't create seperate integer instances. This
is from the point of view of someone who worked most of his career with Java
and that line just makes my eyes bleed. But I can also understand if this
looks like nitpicking to others ;)

------
spullara
Use .equals() like you're supposed to with objects. If you aren't going to use
the primitive types that is really the only good option.

------
efsavage
Autoboxing was the worst thing ever added to Java.

------
morsch
I think making auto-Boxing generate a warning is a bit over the top, but it's
worth it to enable syntax highlighting for it. It just draws your eyes to it
during debugging. I think mine is set to italicize all instances of auto-
boxing. And of course, avoid it where it doesn't smell good.

------
maxs
This is an example of a bug that FindBugs would catch (
<http://findbugs.sourceforge.net/> ). FindBugs is a static source analysis
tool for Java. It's free and open source, no reason not to use it on your
codebase :).

~~~
powatom
Agree 100%, I'm just forgetful and lazy (a winning combination) :P I need to
get it set up to run automatically!

------
extension
This is what operator overloading is for. If equals() should always be used to
compare objects then == should call it.

~~~
wiradikusuma
Java doesn't support operator overloading.

~~~
masklinn
Doesn't java support privileged operator overloading for `+`? (privileged in
that it's only supported for types baked into the runtime itself, much like
generics in Go)

------
funkah
Yuck, what a nightmare. 1000 should equal 1000.

~~~
RobAtticus
It does, but their memory locations need not be the same.

Making the == operator act differently just because the Objects in question
are boxed version of primitives would probably be more of a nightmare than
having the == operator act consistently.

Perhaps a better solution would be a compiler warning so these mistakes can be
identified quicker.

~~~
morsch
Arguably making the == operator mean two different things -- equal in value
and equal in reference -- is the problem to start with. I'd prefer it if ==
was a value comparison in all cases, and reference comparison were mapped to
=== or something. I guess the extra verbosity doesn't get a lot of fans
here...

