At my work we have about 15-20 Java developers working on some kind of project. This week I noticed someones code which was new for me...
If 'bla' is true then this results in a NullPointerException. Why is that so? Is it because the throw keyword expects a Throwable to be specified, which is null in this case, therefore resulting in a NullPointerException?
Dennis Grimbergen wrote:Is it because the throw keyword expects a Throwable to be specified, which is null in this case, therefore resulting in a NullPointerException?
Yes, I'd say you got that right.
If I were supervising the programmer who wrote that I would (1) congratulate them on finding a cute trick like that (2) tell them to change it to actually throw a NullPointerException. After all it's been clearly demonstrated that it's a confusing trick, and clear code is better than short code.
However I'd also say that a design which requires application code to explicitly throw a NullPointerException is itself questionable. As Sagar says, there are better choices if you have to throw an unchecked exception.
I agree it's hideous, but I truly love this thread. How often do you get to see something in Java that you've never seen before? If you're me, anyway, not often. This is truly new and horrible.
I gave it a try. One interesting thing is that the compiler doesn't complain; somehow "null" is interpreted as a RuntimeException, not as a Throwable, so no "throws" clause is required. I have no idea how this could be:
Not surprisingly, the stack trace is indistinguishable from a "natural" one:
Finally, I checked to see if the compiler was special-casing this; it's not:
I am going to invite my favorite language lawyer to come have a look!
Wow - I agree with everyone who said that (a) they have never seen that one before, (b) it's somehow perverse and wrong and should be changed to something more meaningful, and yet (c) it's still cool to see something new and unexpected like this.
I wonder if the author of the code even did this intentionally. Were they maybe confusing throw with return? Did they discover this once accidentally and now they do it for fun? Weird.
The relevant language rules are found at JLS3 14.18:
throw Expression ;
A throw statement first evaluates the Expression. If the evaluation of the Expression completes abruptly for some reason, then the throw completes abruptly for that reason. If evaluation of the Expression completes normally, producing a non-null value V, then the throw statement completes abruptly, the reason being a throw with value V. If evaluation of the Expression completes normally, producing a null value, then an instance V' of class NullPointerException is created and thrown instead of null. The throw statement then completes abruptly, the reason being a throw with value V'.
So yes, surprisingly, they really did this intentionally. Why?
My guess is that they wanted to allow coders some flexibility in how they generate an exception. One might have a helper method that provides a carefully formatted message, or includes a lot of additional data for debug purposes. So you want to be able to write:
and make it nice and concise. But the compiler writers don't want to have to carefully analyze the code for createReallyDetailedException() to determine exactly what it really does, for all possible inputs. They just want to be able to check the declared return type, and make sure it's some sort of Throwable. Well, and they'll further use that information to determine if the callers of this method are throwing any checked exceptions or not. But that's it.
So what about throw null? Isn't that, like, a case where it's incredibly obvious that the Expression is not resulting in a Throwable instance? Well, yes - but it still would have required an additional rule beyond what's already in the JLS in this section. My guess is that no one ever thought it would be an issue. And since this is the first time we've heard of it being an issue, I guess that wasn't too far from the truth.
Paul Clapham wrote:However I'd also say that a design which requires application code to explicitly throw a NullPointerException is itself questionable. As Sagar says, there are better choices if you have to throw an unchecked exception.
Why? I usually throw a NullPointerException when one of my method arguments is null. I use an InvalidArgumentException when they are otherwise invalid. I think it's pretty clear. NPEs commonly happen when you pass null to a function that doesn't allow null values. As a matter of fact, I find this more clear than using an InvalidArgumentException saying that one of the arguments was null.
Would you say the standard classes are poorly designed because they throw NullPointerExceptions? (Not that they aren't, in some cases).
Joined: Mar 05, 2008
I'm not Paul of course, but here are my thoughts:
If (and only if) the problem really is that some method argument was null, then I think it's fine to throw NullPointerException.
If I had designed Java, I'd have preferred to use IllegalArgumentException for this, or perhaps a specific subclass such as NullArgumentException*. I would leave NullPointerException only for things that the JVM throws directly, which basically means that the programmer of the current method screwed up. As opposed to the programmer of the code that called this method, which is what IllegalArgumentException is for. It's a way of saying I didn't screw up; the person who called me did. Of course, that person might still be me - but I'm at least going to try to transfer the blame.
However, at this point, plenty of libraries use NullPointerException to indicate a null argument; it's pretty much the standard Java idiom nowadays. So I would follow this practice rather than try to change it.
I would encourage people to do more than just throwing an NPE though. Give it a meaningful message. In particular, the one thing we generally need to know in order to fix this is: what's the name of the parameter that's null? Give a nice clear message:
* When I mentioned NullArgumentException, I thought I was making it up. Or rather, it's an idea I and others have talked about in the past, but it's not in the standard Java libraries. However it turns out it is in Apache Commons now: org.apache.commons.lang.NullArgumentException. Complete with mandatory name of the null argument. Excellent. So yeah, consider using this.