This is an example that was shown to me back in the day when I was at the university. I took a great class ‘Anatomy of Java virtual machine’ taught absolutely brilliantly by prof. Grzegorz Czajkowski  (at the time working for SUN but soon after moving to Google) where we got to play with raw java bytecode and write our own (simple) garbage collectors. Quite challenging for a student but a lot of fun nevertheless.

Anyway, here’s a piece of code:

What will be the result of executing it ?

As expected – a lot of console output.

What if we change the value of the integers a bit ?

Will the output change ?

After running this the program terminates instantly with no output!  (By the way, the incrementation  is not necessary, we could simply start with 128)

It’s the only known to me example where the value has such impact on flow control (if you know any other interesting ones, drop me an email).

It’s all got to do with Boxing/Unboxing and a certain specific caching feature of Java. Let’s dissect it a bit. First of all, let’s look at the conditional statement:

i<j || i>j || i==j

remember, those are Integers, not ints i < j and i > j will force auto unboxing so the comparison will happen with unboxed ints. The == equality comparison however will happen for Integer types and will compare the references. That explains why we get no output for 128 – i and j are simply two different Integer objects, so the reference comparison produces false.

Why then if we set the value to 127 (or 10 for example) do we get an infinite loop ? JVM caches the Integers between -128 and 127 and when you use one of those, it uses a cached one instead of creating new Integer object every time. It’s actually a part of JLS (Java Language Specification) – 5.1.7 Boxing Conversion states “If the value p being boxed is truefalse, a byte, a char in the range \u0000 to \u007f, or an int or short number between -128 and 127, then let r1 and r2 be the results of any two boxing conversions of p. It is always the case that r1 == r2.”

Java 1.6 from certain update allows for specifying the upper threshold of the cached range – by using -XX:AutoBoxCacheMax=<size> JVM option

Some use this example as an argument that you should always use Integer.valueOf() instead of autoboxing. I think you just need to be careful and aware of such behaviors.

EDIT: Check out this blog post: It’s explaining how the Integer caching has changed through different versions of Java