In this specific scenarios, are asserts more appropriate then exceptions?
It is my understanding that assert should be used when program is FUBAR to a degree where it can not recover and will exit.
I also was told to always throw exceptions for clarity and error message handling.
Is there a fine line between when to use each? Is there an example where assert must be used in place of exception unconditionally?
public void subscribe(DataConsumer c) throws IllegalArgumentException {
if (c == null) {
// Almost certainly FUBAR
throw new IllegalArgumentException("Can't subscribe null as a DataConsumer. Object not initialized");
}
if (dataConsumerList == null) {
// Definetely FUBAR
throw new IllegalArgumentException("Nothing to subscribe to. DataConsumerList is null");
}
dataConsumerList.add(c);
}
Personally I'm not keen on using assertions for this sort of thing, simply because they can be turned off. Some places use assertions when running tests, but then disable them for production for the sake of speed. To me this is like taking your driving test as normal, but then removing your seatbelt when you get on the motorway.
An assertion is only going to throw an exception anyway, of course. If you absolutely want to take the JVM down right now, you'd need to use something like Runtime.halt
.
So I'm a fan of exceptions here, although I'd typically use a NullPointerException
when given a null argument, and if dataConsumerList
is part of your state then I would personally use IllegalStateException
to differentiate that situation. (It's a shame that Java doesn't have the same ArgmentNullException
that .NET has, given what a common check it is.)
Guava has the useful Preconditions
class which lets you write this more concisely:
public void subscribe(DataConsumer c) throws IllegalArgumentException {
Preconditions.checkNotNull(c,
"Can't subscribe null as a DataConsumer. Object not initialized");
Preconditions.checkState(dataConsumerList != null,
"Nothing to subscribe to. DataConsumerList is null");
dataConsumerList.add(c);
}
General rule (copied from here)
assertions should protect from (not always obvious) mistakes of the
developer, e.g. using a pointer despite its being NULL.
exceptions are a way to handle errors that may legitimately occur at
runtime, e.g. the failure of trying to connect to some server (which may
not respond for various reasons).
And there is a better way of writing the above code using google-guava Preconditions.checkNotNull() class.
public void subscribe(DataConsumer c) throws IllegalArgumentException
{
checkNotNull(c, "Can't subscribe null as a DataConsumer. Object not initialized");
checkNotNull(dataConsumerList , "Nothing to subscribe to. DataConsumerList is null");
dataConsumerList.add(c);
}
If you could put this in English terms, use assert for "gotta" (Got to, Must) and exceptions for "otta" (Ought to, should).
Use the assert for show-stopping, critical conditions that must be true for the execution to continue. Examples might be that a division happens correctly (think of the Intel chip floating point bug) or that your database connection is not null after you have correctly opened it. If these have occurred, then program execution should not continue.
Use the throw for foreseeable errors that your method may handle. The throw is a part of a contract that declares to you and other programmers that certain types of errors may be encountered (and that it's not your responsibility).
In your example, my guess is that a null consumer or an empty list should never happen under normal circumstances. If my guess is correct, then you would want to use an assert here, declaring that subscribe() will handle it.
If my guess is wrong and a null consumer happens, say 1 out of 50 times, then the throw would be better and you would be declaring that subscribe() forms a contract with a calling method, whereby the calling method handles the error.
The Java technote Programming With Assertions contain this explicit line in with regards to usage:
Do not use assertions for argument checking in public methods.
That should be a pretty definitive answer to your question.