Skip to main content

Java Puzzler

I bought the book Java Puzzlers by Josh Bloch and Neal Gafter a few years ago and enjoyed it. If you aren't familiar with it, it covers rare, odd and usually counter-intuitive edge cases of Java in a brain-teaser style of presentation. For both a Java user and an analytical mind its a fascinating book.

Well today I stumbled onto a puzzler of my own and thought I'd share. Can you tell me what the main method of this class will output?
1 : public class Parser {
2 :
3 : private static <T> T parse(String s, Class<T> type) {
4 : // Simple implementation only supports long primitive
5 : if(type == long.class) {
6 : return (T) Long.parseLong(s);
7 : }
8 : throw new UnsupportedOperationException(
9 : "parse() only supports long right now!");
10: }
11:
12: public static void main(String[] args) {
13: System.out.println(parse("1234", long.class).equals(1234));
14: }
15: }

So what gets written to standard output? If you said 'true', then you'd be wrong. If you said 'false', then you'd also be wrong! The code above won't even compile! There are a few features of Java that are colliding here to give odd results, including generics, type erasure, primitive types and autoboxing.

So what happens exactly? You'll get a compile error like this:
Error:line (6) inconvertible types
found : long
required: T
The error is on the return statement line of the parse() method. Long.parseLong() returns a primitive long, but since a parameter type can only represent an Object type, you can't cast a primitive to an parameter type. Also, it appear auto-boxing doesn't work in this case, so it fails with a compiler error.

But wait, doesn't the code explicitly use the Class object that represents the long primitive, long.class? But see 'long.class' is syntactic sugar for the constant field Long.TYPE which is of the parameterized type Class<Long> since type variables only support using Objects.

So realizing this, we can change the return statement to use a Long instead of a long:
    return (T) Long.valueOf(s);
Now the code will compile, but something is still wrong because it prints out 'false'.

Knowing that the return type of parse("1234", long.class) is Long, take another look at the puzzle. Can you see the problem? This one is subtle. The numeric literal '1234' that is inside the call to equals() needs to be auto-boxed and since it is a literal int, it is boxed into a Integer. But an Integer object isn't considered equal to a Long object because they are different types, so equals() returns false.

So it a few interesting features combine for some strange behavior. Hope you enjoyed this puzzle!

Comments

Neal Gafter said…
Most of the puzzlers in our book aren't rare; in fact, they're taken out of actual problems people have encountered while writing production code. However, the issues are distilled to their essence in the book.
My apologies if I mischaracterized it. It is a great book and one I recommend to other programmers as a must-read because its so informative and accessible.

Popular posts from this blog

3D Photo Viewer for Looking Glass

The Looking Glass I created my first Chrome extension, which is now live on the Chrome Web Store ! It's built for the Looking Glass , a holographic display that let's you view three-dimensional objects without glasses. I've also opened the source to the extension on GitHub. The Chrome extension allows you to view Facebook's "3D Photos", a feature they added in 2018 for displaying photos that include a depth map like those from phones with dual cameras, such as Apple's "Portrait Mode". Getting Started To use the extension, connect your Looking Glass to your computer, navigate to Facebook and open the viewer from the extension's popup menu. This will open a browser window on the Looking Glass display's screen in fullscreen mode. Opening the Viewer Once the viewer is open, the extension watches for any 3D Photo files being downloaded, so browse around Facebook looking for 3D Photos.  I recommend some of the Facebook groups de...

First Impressions from NoSQL Live

Today I drove up to Boston for the day to attend NoSQL Live . My experience so far within the NoSQL community has been limited to what we've built in-house at Disney and ESPN over the past decade to solve our scaling issues, more recently has been ESPN's use of Websphere eXtreme Scale , and the very latest has been my own experimentation with HBase which hasn't gotten much further than setting up a four node cluster. I've read a little about Cassandra, memcached, Tokyo Cabinet and that's about it. So before the sandman wipes away most of my first impressions of the technologies discussed today, I wanted to record my thoughts for posterity or, at the very least, tomorrow. Cassandra Cassandra seems to be the hottest NoSQL solution this month with press about both Twitter and Digg running implementations. My impression, I'm wary of "eventual consistency". I don't feel I understand the risk and ramifications well enough to design a system properly...

My Journey to Fitness, a 5K, and my first Triathlon

At the finish line My name is Brian and Sunday I became a triathlete. My journey started ten months ago when I decided to get back into shape after 15 years of being obese and out-of-shape with some yo-yo dieting in the middle. What changed? I'll get to that. This weekend I competed in the first ever Rocketman Florida Triathlon which took place on the grounds of Kennedy Space Center at Cape Canaveral. In preparation I lost 50 lbs and 12 inches from my waist. But I'm getting ahead of myself. I'm a huge space buff. As a kid I wanted to become an astronaut. I went to Space Camp in Titusville when I was 10. Before that, I saw my first shuttle launch at 7 while on vacation. It was the final launch of the Challenger. I've written about that experience . I've seen three other launches since then including John Glenn's famous return to space as well as the final launch that ended the U.S. Shuttle Program. The idea of biking on the restricted grounds ...