Saturday, August 28, 2010

Double.valueOf does NOT cache instances!

I had one of those lightbulb moments where I asked myself, "You know, I wonder how Double.valueOf implements the caching... Or does it???".

The documentation is an obvious place to look for information, of course:
public static Double valueOf(double d)

Returns a Double instance representing the specified double value. If a new Double instance is not required, this method should generally be used in preference to the constructor Double(double), as this method is likely to yield significantly better space and time performance by caching frequently requested values.
No obvious "frequently requested values" come to mind, aside from perhaps the NaN, the signed zeroes, the signed ones, and the signed infinities. Perhaps MIN/MAX_VALUE and MIN_NORMAL are also worth caching, since they at least do have the privilege of being defined as class constants.

Either way, it's not as simple as having an array the way e.g. Integer instances are cached by Integer.valueOf for values around zero.

In my pursuit to uncover what is actually cached and how, I went straight to the source code.
public static Double valueOf(double d) {
    return new Double(d);
}
Ladies and gentlemen, we have been duped.

Here's what JLS 5.1.7 Boxing Conversion specifies:
If the value p being boxed is:
  • true, false,
  • 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.
So at least the spec isn't being violated. Which isn't what can be said about me.

It's worth noting that at least in the OpenJDK version cached by Google Code, Long.valueOf caches (Long) [-128L, 127L], despite no explicit requirement by JLS to do so. Unfortunately, unlike Integer, you CAN'T set the upper range with -XX:AutoBoxCacheMax=<size> option.

It'd be interesting to figure out what the best way to implement this feature more cleanly across all the box classes for the integral numeric types would be. I'm thinking it'd probably have to be an aspect-oriented programming approach.

No comments:

Post a Comment