Java Forum / General / January 2008
NullPointerException, IllegalArgumentException, or AssertionError for null constructor argument
Daniel Pitts - 28 Dec 2007 22:11 GMT I have a constructor that takes a String argument. I'd like to throw an exception if the constructor is invoked with a null argument, but I'm not sure which instruction I should use. NullPointerException is technically accurate, since it is a null pointer, but it is also an IllegalArgumentException. I think that IllegalArgumentException is more specific, so I'll probably go with that, but wanted opinions.
The third option is AssertionError. I could just use assert arg!=null, and that could be enough. This is for a personal project, so it doesn't *really* matter, but at the same time its good practice for me to think about these sort of things :-)
Thoughts?
Thanks, Daniel.
 Signature Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
Owen Jacobson - 28 Dec 2007 22:21 GMT On Dec 28, 2:11 pm, Daniel Pitts <newsgroup.spamfil...@virtualinfinity.net> wrote:
> I have a constructor that takes a String argument. I'd like to throw an > exception if the constructor is invoked with a null argument, but I'm [quoted text clipped - 10 lines] > > Thoughts? Thoughts: private members get assertions if anything at all for parameter checking (as well as other invariants); public members get explicit tests if it matters that parameters meet specific requirements. I tend to leave NPE to the java runtime to throw and use IllegalArgumentException for things caught in explicit tests.
Asserts can, after all, be turned off.
Throwing AssertionError explicitly seems like the Wrong Thing. :)
Lew - 29 Dec 2007 03:15 GMT > On Dec 28, 2:11 pm, Daniel Pitts > <newsgroup.spamfil...@virtualinfinity.net> wrote: [quoted text clipped - 22 lines] > > Throwing AssertionError explicitly seems like the Wrong Thing. :) It is. It is completely contrary to the purpose of the 'assert' mechanism, and it's an Error, not an Exception. The 'assert' mechanism is not meant for runtime checks of data, but for test-time checks of algorithmic correctness.
The great third phase of programming I don't see mentioned much is test-time. Everyone talks about compile-time and run-time, but 'assert' is a leader in test-time functionality.
Again, its purpose is to check the algorithm, not the data.
 Signature Lew
Eric Sosman - 28 Dec 2007 22:38 GMT > I have a constructor that takes a String argument. I'd like to throw an > exception if the constructor is invoked with a null argument, but I'm [quoted text clipped - 8 lines] > *really* matter, but at the same time its good practice for me to think > about these sort of things :-) IllegalArgumentException would get my vote, with a possible last-minute in-the-voting-booth defection to NullPointerException. AssertionError is the candidate whose placards I'd tear down, no matter what the election authorities might think.
 Signature Eric Sosman esosman@ieee-dot-org.invalid
Patricia Shanahan - 28 Dec 2007 22:41 GMT >> I have a constructor that takes a String argument. I'd like to throw >> an exception if the constructor is invoked with a null argument, but [quoted text clipped - 13 lines] > AssertionError is the candidate whose placards I'd tear down, no > matter what the election authorities might think. Agree with this, with the possible addition of a merger between the two acceptable options - throw an IllegalArgumentException with a NullPointerException as cause. However, IllegalArgumentException with a clear message should normally do the job.
Patricia
Arne Vajhøj - 29 Dec 2007 01:26 GMT > I have a constructor that takes a String argument. I'd like to throw an > exception if the constructor is invoked with a null argument, but I'm [quoted text clipped - 3 lines] > IllegalArgumentException is more specific, so I'll probably go with > that, but wanted opinions. IllegalArgumentException
Because
NullPointerException : tells me that the code called a member on the argument without checking it first
IllegalArgumentException : tells me that code checked the argument first
and the second one is the correct.
Arne
tzvika.barenholz@gmail.com - 29 Dec 2007 18:20 GMT On Dec 29, 12:11 am, Daniel Pitts <newsgroup.spamfil...@virtualinfinity.net> wrote:
> I have a constructor that takes a String argument. I'd like to throw an > exception if the constructor is invoked with a null argument, but I'm [quoted text clipped - 15 lines] > -- > Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/> I vote NPE. It's more specific, and basically it's what it's there fore. IAE could mean any number of things. Of course if you decide on NPE, you don't actually have to check in the constructor and explicitly throw NPE - just let it be thrown on method calls. This is more general, in that it allows construction with null, then calling setXXX with a legal value, which is useful for some complex objects. T
Patricia Shanahan - 29 Dec 2007 18:25 GMT > On Dec 29, 12:11 am, Daniel Pitts > <newsgroup.spamfil...@virtualinfinity.net> wrote: [quoted text clipped - 20 lines] > I vote NPE. It's more specific, and basically it's what it's there > fore. IAE could mean any number of things. IAE means that an argument was invalid, and the Javadoc comments should give the rules.
Even if the Javadocs indicate that NPE can be caused by a null argument, short of reading the code, the caller has no way of knowing if the NPE is due to that, or due to some other problem in the called code. There are far too many things that cause NPE.
If you are worried about explaining what was wrong with the argument, you could report the NPE as cause on the IAE. In any case, the message should be clear.
Patricia
Lew - 29 Dec 2007 18:51 GMT > Of course if you decide on NPE, you don't actually have to check in > the constructor and explicitly throw NPE - just let it be thrown on > method calls. This is more general, in that it allows construction > with null, then calling setXXX with a legal value, which is useful for > some complex objects. Bad advice.
If construction with null is allowed, then it should never throw an NPE, inside the constructor or passed through to the caller. If you need special handling for null, use if ( foo == null ) not an NPE, to check for it.
Certainly the constructor shouldn't pass through any exceptions without a logging discipline. (Nor should any method.)
Checked exceptions are a good way to ensure that client code will handle the exception thrown by a constructor or method.
 Signature Lew
tzvika.barenholz@gmail.com - 30 Dec 2007 09:15 GMT > tzvika.barenh...@gmail.com wrote: > > Of course if you decide on NPE, you don't actually have to check in [quoted text clipped - 19 lines] > -- > Lew On second thought, when construction with null is allowed, then subsequent method calls *could* reasonably throw IllegalStateException if the object is still null when they need them. Still, I like to call a spade a spade, so when something fails because a pointer is null, it makes sense to let NPE be thrown.
As for your objection to non-checked exception here, it is valid of course. But most java programmers will probably frown at having to try- catch around a method call just for the case that the object reference they pass is null, when they know for a fact it isn't.
T
Lew - 30 Dec 2007 15:47 GMT > On second thought, when construction with null is allowed, then > subsequent method calls *could* reasonably throw IllegalStateException > if the object is still null when they need them. Still, I like to call > a spade a spade, so when something fails because a pointer is null, it > makes sense to let NPE be thrown. Lew wrote:
>> Checked exceptions are a good way to ensure that client code will handle the >> exception thrown by a constructor or method.
> As for your objection to non-checked exception here, it is valid of course. Rrr?
How do you derive an "objection" to unchecked exceptions, much less attribute such to me?
Such an objection most emphatically is not valid. Of course.
> But most java [sic] programmers will probably frown at having to try- > catch around a method call just for the case that the object reference > they pass is null, when they know for a fact it isn't. Most Java programmers are very junior in their craft. Anyway, checked exceptions are for when you don't "know for a fact it isn't"; unchecked exceptions are for when you should have known better. Checked exceptions are more for runtime conditions that the API insists that the client handle. Unchecked exceptions are for programming mistakes, mostly. Errors are just to let you log some desperate cry for maintenance before crashing.
It is up to the API designer to design the API. Part of a method's design, arguably the most important part, is its method signature. If it is important for a client of the method to handle an exception, Java provides the checked exception as the way for the API designer to ensure it. The irritation of lazy, unenlightened programmers is not a consideration.
If a designer is too lax or too strict in their design, that is a designer's error. Designers are responsible for their errors, and indeed some of the best APIs have design flaws. For example, java.util.Date.
For an API designer to avoid designing checked exceptions is bad, bad. With every method you design you have a choice - throw no exceptions, throw one or more unchecked exceptions, throw one or more checked exceptions, or a combination of the latter two. (There isn't much need to design Error into the signature. If I think I need to design an Error, I'm going to rethink the situation.)
Your choice is determined by your intention for the API. What invariants must you maintain? Must a client deal with exceptions, as, say, for IOExceptions thrown by a Stream? You certainly want to ensure that clients are aware of the likelihood of an exception, and guarantee that they have code in place to deal with it. Could there be more than one exceptional condition so different that they need different Exception types? See Class.newInstance(). Might the problem be actually uncatchable, but still so important that it belongs in the signature? That's an Error, folks, as from Class.forName().
Notice that checked exceptions are mostly responses to run-time conditions - they do not represent programmer mistakes. Unchecked exceptions tend to happen for things the programmer can control, like whether a variable is null. (Assertions are to check algorithmic invariants.)
Some exceptions are fundamental and essentially controllable by the client programmer. Invoking 'new Integer("Snark")' or 'Integer.valueOf("Snark")' throws a RuntimeException, to be caught by the programmer that they may fix their own mistake. Integer really should not throw a checked exception here.
Be careful about reading into people's comments things that not only they did not say, but with which they disagree.
 Signature Lew
Mark Rafn - 29 Dec 2007 22:23 GMT >On Dec 29, 12:11 am, Daniel Pitts >> I have a constructor that takes a String argument. I'd like to throw an >> exception if the constructor is invoked with a null argument ...
>I vote NPE. It's more specific, and basically it's what it's there I vote IllegalArgumentException. NPE implies a bug or unexpected state inside the code, where IAE makes it clear that the bug is in the code making the call.
AssertionError is right out. Assertions exist to make low-severity bugs into high-severity ones so you can find and fix them. They're not part of an API design. -- Mark Rafn dagon@dagon.net <http://www.dagon.net/>
Lew - 29 Dec 2007 23:38 GMT > AssertionError is right out. Assertions exist to make low-severity bugs into > high-severity ones so you can find and fix them. They're not part of an API > design. I agree with your conclusion, but quibble over a detail. Assertions do not "exist to make low-severity bugs into high-severity ones" at all. They exist to verify pre- and post-conditions to ensure algorithmic correctness. The bugs, if any, that are thus discovered will have been "high-severity" bugs all along. Assertions exist to make such high-severity issues visible to testers and developers before they are visible to customers. Assertions usually are and generally should be disabled in production, very much unlike exceptions.
The difference between exceptions and assertions is that they test for different things at different points in the application lifecycle. Exceptions handle anomalous data and like conditions at run-time. Assertions handle incorrect algorithms at test-time.
 Signature Lew
John W. Kennedy - 30 Dec 2007 04:57 GMT >> AssertionError is right out. Assertions exist to make low-severity >> bugs into [quoted text clipped - 15 lines] > Exceptions handle anomalous data and like conditions at run-time. > Assertions handle incorrect algorithms at test-time. Remember how people used to complain about parity-checked ROM?
 Signature John W. Kennedy A proud member of the reality-based community.
Lew - 30 Dec 2007 05:01 GMT >>> AssertionError is right out. Assertions exist to make low-severity >>> bugs into [quoted text clipped - 17 lines] > > Remember how people used to complain about parity-checked ROM? Please refresh our collective memories on this matter. I for one am quite interested. Why did people complain about parity-checked ROM? Do they still, and if not, why not?
A few words of how that ties in might not be remiss.
 Signature Lew
John W. Kennedy - 30 Dec 2007 23:33 GMT >>>> AssertionError is right out. Assertions exist to make low-severity >>>> bugs into [quoted text clipped - 23 lines] > > A few words of how that ties in might not be remiss. Whoops! That should have been "RAM".
 Signature John W. Kennedy Read the remains of Shakespeare's lost play, now annotated! http://pws.prserv.net/jwkennedy/Double%20Falshood/index.html
Lew - 31 Dec 2007 03:06 GMT >>> Remember how people used to complain about parity-checked ROM? Lew wrote:
>> Please refresh our collective memories on this matter. I for one am >> quite interested. Why did people complain about parity-checked ROM? >> Do they still, and if not, why not? >> >> A few words of how that ties in might not be remiss.
> Whoops! That should have been "RAM". Please refresh our collective memories on this matter. I for one am quite interested. Why did people complain about parity-checked RAM? Do they still, and if not, why not?
A few words of how that ties in might not be remiss.
 Signature Lew
Patricia Shanahan - 31 Dec 2007 03:13 GMT >>>> Remember how people used to complain about parity-checked ROM? > [quoted text clipped - 12 lines] > > A few words of how that ties in might not be remiss. The problem with parity, as distinct from ECC, is that all you can do if it detects an error is abort anything that is affected by the location showing the error. However, arguably that is better than not having any error detection. In most cases, a wrong answer is worse than an abort.
Patricia
John W. Kennedy - 31 Dec 2007 05:25 GMT >>>> Remember how people used to complain about parity-checked ROM? > [quoted text clipped - 12 lines] > > A few words of how that ties in might not be remiss. Weren't you on-line in the mid-80s? "I don't want this dumb parity checking; it makes my system crash," was even more popular than, "My computer must be broken, because 1/3 + 1/3 + 1/3 is coming out 0.999999 instead of 1.0."
 Signature John W. Kennedy "There are those who argue that everything breaks even in this old dump of a world of ours. I suppose these ginks who argue that way hold that because the rich man gets ice in the summer and the poor man gets it in the winter things are breaking even for both. Maybe so, but I'll swear I can't see it that way." -- The last words of Bat Masterson
Mark Rafn - 30 Dec 2007 07:27 GMT >> AssertionError is right out. Assertions exist to make low-severity bugs into >> high-severity ones so you can find and fix them. They're not part of an API >> design.
>I agree with your conclusion, but quibble over a detail. Assertions do not >"exist to make low-severity bugs into high-severity ones" at all. I was being glib, but there is some truth behind my statement. The reason to have assertions in code (as opposed to just comments, or non-assertion conditions that throw exceptions, is to ensure that a mismatch between the developer's expectations and reality causes an event that's very hard to miss.
>They exist to verify pre- and post-conditions to ensure algorithmic >correctness. The bugs, if any, that are thus discovered will have been >"high-severity" bugs all along. Yes. It might be clearer to say that assertions turn logic bugs into crash bugs. That crash bugs are higher severity than more subtle misbehavior is not universal.
>The difference between exceptions and assertions is that they test for >different things at different points in the application lifecycle. Exceptions >handle anomalous data and like conditions at run-time. Assertions handle >incorrect algorithms at test-time. Agreed. -- Mark Rafn dagon@dagon.net <http://www.dagon.net/>
Lew - 30 Dec 2007 17:04 GMT Lew wrote:
>> I agree with your conclusion, but quibble over a detail. Assertions do not >> "exist to make low-severity bugs into high-severity ones" at all.
> I was being glib, but there is some truth behind my statement. The reason to > have assertions in code (as opposed to just comments, or non-assertion > conditions that throw exceptions, is to ensure that a mismatch between the > developer's expectations and reality causes an event that's very hard to > miss. Specifically, expectations and reality in the domain of algorithmic invariants and like issues. Contrast to exceptions, that expose such a mismatch in the domain of data correctness or environmental conditions.
> It might be clearer to say that assertions turn logic bugs into crash bugs. Contrast to exceptions, that turn data or environment bugs into recoverable bugs.
> That crash bugs are higher severity than more subtle misbehavior is not universal. I'm not sure that seeing "DangerDangerException ... [stack trace]" on a user's screen is subtle misbehavior. Maybe compared to having a klaxon go off in conjunction?
Assertions turn crash bugs into logged, analyzable crash bugs, and they do it before you go into production.
If I translate "severity" into "visibility" I agree with your characterization of assertions. I was using a different definition of "severity".
The quibble has vanished in the bright light of agreement.
 Signature Lew
Zig - 30 Dec 2007 04:25 GMT > I have a constructor that takes a String argument. I'd like to throw an > exception if the constructor is invoked with a null argument, but I'm [quoted text clipped - 3 lines] > IllegalArgumentException is more specific, so I'll probably go with > that, but wanted opinions. There's been some good advice from other posters here, but I thought I'd throw in a couple observations.
From java.lang.NullPointerException:
"Thrown when an application attempts to use null in a case where an object is required. These include: ... Applications should throw instances of this class to indicate other illegal uses of the null object."
Next, we know that a constructor is a special kind of method, so let's assume that the convention for checking arguments on a method is the same as the convention for checking arguments on a constructor. With a little bit of poking around, we see methods like java.lang.Enum.valueOf
Throws: IllegalArgumentException - if the specified enum type has no constant with the specified name, or the specified class object does not represent an enum type NullPointerException - if enumType or name is null
If you also want to see a constructor: java.lang.StringBuilder(String)
Throws: NullPointerException - if str is null
Given that, it appears that Sun's convention is to throw a NPE whenever a null is found where it shouldn't be. IllegalArgumentException seems to be better suited in cases where the arguments can only be within a subset of the values allowed by type of the argument.
As this would seem to be a matter of convention, I've cited Sun's, but Sun's is not the only convention. SWT programmers seem to like using
throw new SWTException(SWT.ERROR_NULL_ARGUMENT); or throw new SWTException(SWT.ERROR_INVALID_ARGUMENT); or even throw new SWTException(SWT.ERROR_CANNOT_BE_ZERO); etc.
HTH,
-Zig
Lew - 30 Dec 2007 04:59 GMT > Next, we know that a constructor is a special kind of method, There are many important differences between a constructor and a method, of sufficient magnitude that it is more useful to think of constructors not being methods at all.
They do, however, share the ability to receive parameters and throw exceptions with methods. Zig's main point about argument checking is therefore completely applicable, of course.
With respect to the rest of those points, let me warn that Sun's libraries are not free of unfortunate choices. They may not always represent current best practices.
The choice of NPE or IllegalArgumentException is the classic Java angel's ball [1] on the head of a pin. You should use NPE when you decide that users of your library should be primarily aware of the nullness of the argument. You should use IllegalArgumentException when you decide that users of your class should be primarily aware of its illegality. You use the latter with the former as a cause when you decide that users should be primarily aware of the illegality and that it's illegal on account of nullness. The driver of your choice is your what you will for client classes to experience.
Personally, I choose the third, combination option for clients of my code pretty much always, because pretty much always it's the nature of the argument as an argument that's important for the client class to track, and whether it's legal is the first consideration, why it's illegal the second.
[1] ball in the sense of a formal dance.
 Signature Lew
Roedy Green - 31 Dec 2007 03:52 GMT On Fri, 28 Dec 2007 14:11:42 -0800, Daniel Pitts <newsgroup.spamfilter@virtualinfinity.net> wrote, quoted or indirectly quoted someone who said :
>IllegalArgumentException. that is what Sun tends to use for anything wrong with parms.
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Lew - 04 Jan 2008 04:58 GMT > I have a constructor that takes a String argument. I'd like to throw an > exception if the constructor is invoked with a null argument, but I'm [quoted text clipped - 10 lines] > > Thoughts? Here's an example of the difference between assertion and exception generation. The assertion is forced to hold by the exception handling. If the exception-handling algorithm were wrong, the null could perhaps slip through, and the assert would fail. This should never happen.
The assert is there to alert us if the exception failed to do its job. The programmer is asserting that the exception clause is sufficient.
public class NoNullHolder <T> { private final T held;
public NoNullHolder( T toHold ) { if ( toHold == null ) { throw new IllegalArgumentException( new NullPointerException( "null toHold" )); } held = toHold; assert held != null; // postcondition invariant }
public final T getHeld() { assert held != null; // precondition invariant return held; } }
 Signature Lew
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|