Pure Danger Tech


Array puzzler

27 Mar 2007

I learned some interesting things about the Arrays class in JDK 1.5 today from the presentation

The Continuing Adventures of Java™ Puzzlers: Tiger Traps by Josh Bloch and Neal Gafter. Specifically puzzler #7 “Fib O’Nacci”. I’ll cut to the chase and just show the heart of it – consider this example in Java 5:

System.out.println(Arrays.asList(new int[] { 1, 2, 3 }));

You might expect that this prints [1, 2, 3] because in JDKs prior to Java 1.5, it did. But in Java 5, you’ll instead get something like [[I@10b62c9]. The reason is that in Java 1.5, Arrays.asList() was changed to take a varargs. That’s really cool because you can then create lists like this (taking advantage of autoboxing as well):

List list = Arrays.asList(1, 2, 3, 4, 5);

But it really sucks in this case because varags only works with arrays of Object refs. Since in the puzzler we’re passing an array of primitives, the entire array is treated as the first item in the varargs array and this is effectively equivalent to Arrays.asList(new Object[] { new int[] { 1, 2, 3} }), which explains why you see an array containing the typical gross array toString in the result.

So, this was a bit of a goof. I listened to a podcast version of this same presentation from java.no and Josh said this was his fault, but I guess it was not discovered until too late. He also mentioned that there are a host of new methods on the Arrays class, which I was not previously aware of. Specifically, there are toString, equals, hashCode, deepToString, deepEquals, and deepHashCode methods, all of which are overloaded to handle both primitive and Object arrays.

So, if you are using Arrays.asList() specifically to get a printable version of the array (a common usage), you can instead use the toString() method, which will work for any array type in JDK 1.5:

System.out.println(Arrays.toString(new int[] { 1, 2, 3 }));

This will, as expected, print [1, 2, 3]. The deep versions can be used to print, compare, and create hashcodes for arrays of arrays (matrices), etc. So, I’m sure I’ve got code somewhere that’s doing this gross work for arrays which can now be simplified.

On a tangent, why doesn’t the array toString actually print something useful in the first place so that we could just say:

System.out.println(new int[] { 1, 2, 3});

and not have to involve the Arrays class? Same with equals and hashCode. Is there some reason arrays shouldn’t work more like collections? That’s always seemed goofy to me.