I was working on a project and needed to get a Long value from a String. I know the Long class (like the other wrapper classes for primitives) has static methods that do just the thing , so I started typing in my IDE and trusted that I’d find one that worked. As it turns out there are several methods that do similar conversions. Here’s a list of the candidates:
Long.decode(String nm)
Long.getLong(String nm)
Long.parseLong(String nm)
Long.valueOf(String nm)
So, given that each of these takes a String and returns a Long, what does the following code return? (Notice that the getLongValue() method returns a primitive long:
public long getLongValue() {
Long value = Long.getLong("23");
return value.longValue();
}
Here’s the list of possible answers:
A) 23L
B) 0L (zero)
C) It depends.
Before you continue reading, what do you think the right answer is… OK, that’s enough thinking. Let’s take a look at the possible answers and see what seems likely.
Now it seems reasonable that Long’s getLong() method should return the value of the String as a Long, so answer ‘A’ looks pretty good. Then again, if it were that easy why would I bother posting this. Answer ‘B’ doesn’t seem very reasonable - unless getLong() isn’t really converting the value of the String. So that leaves answer ‘C’ as the primary suspect. If you’re familiar with Josh Bloch’s Java Puzzler talks from JavaOne, you’ll probably go with ‘C’ because it is kind of vague and that makes it a safe bet.
And you’d be right. The correct answer is ‘C’.
It turns out that Long.getLong() doesn’t try to convert the value of the passed in String directly. It looks for a System property with that name, retrieves the value associated with it, and converts that. So what the getLongValue() method returns depends on the value of the System property “23″. So, what if there is no System property “23″? In that case, the method throws a null pointer exception because Long.getLong() will return a null. Ouch!
I found this the hard way. I needed to convert a String and picked a likely method from the list provided by my IDE. I was greatly surprised when my unit test failed, so I looked up the JavaDoc on it and realized my mistake.
There are a few morals to this story:
Unit tests are your friends.
Use the JavaDoc, and make sure you write some
for people using your code.
Hurrying can cause unexpected delays; but those
can become fodder for a blog post.
Until next time, I leave you with the traditional Java Puzzler farewell,
“Don’t code like my brother.”
I can't tell you how many people I've spoken to have had exactly the same problem with this method and the others like it. I really don't like these methods and find them rather pointless. I would have thought they'd have been better placed on the Properties class, but that's another example of horrid code.
ReplyDeleteThere are a few morals to this story:
ReplyDeleteMethods that behave on unstated free variables are awful. Worse, this kind of idiocy is the very thesis of imperative programming.
The moral is, do away with these languages that ensure perpetual error on behalf of even the most vigilant user.
getLong would be better if it took a String and a Properties, instead of quietly looking at global variables.
ReplyDeletePramatr,
ReplyDeleteThere do seem to be a lot of seemingly pointless methods out there that just add to the complexity of the SDK.
On the other hand, I could've made use of the autoboxing and unboxing feature added in Java 5, but I didn't and that led to the interesting problem and eventually to this blog posting.
Thanks for the comment, I definitely appreciate feedback!
Burk
Tony,
ReplyDeleteInteresting take on the problem, but I don't see how it's a language issue. To me it seems like a problem with the method names.
If Long.getLong() had been named getLongFromSystemProperties() there would have been no confusion on my part and no puzzle to post.
I suspect that anyone could create a similar issue in most any language.
Thank you for your attention and taking the time to post a comment.
Burk
Ricky,
ReplyDeleteInteresting idea. Even though getLong() could access the system properties directly, making it a parameter to the method would be a strong signal to the user that this is not the method to use if you just want to pull the value from the string itself.
It seemed odd at first, but I'm liking the idea the more I think about it.
Thanks for suggesting it,
Burk