views:

298

answers:

9

Is it better to return a null value or throw an exception from an API method?

Returning a null requires ugly null checks all over, and cause a major quality problem if the return is not checked.

Throwing an exception forces the user to code for the faulty condition, but since Java exceptions bubble up and force the caller code to handle them, in general, using custom exceptions may be a bad idea (specifically in java).

Any sound and practical advice?

+2  A: 

I think the answer is entirely dependent on the context of your application, and what you consider to be an "exceptional circumstance" versus programmer error.

For example, if writing an XML parser you may choose to implement methods like:

/**
 * Returns first child element with matching element name or else
 * throws an exception.  Will never return null.
 */
Element getMandatoryChildElement(Element parent, String elementName)
throws MissingElementException;

... as this approach allows you to implement your message parsing code in a single block of logic, without having to check that the message is well-formed after retrieving each element or attribute.

Adamski
@Adamski - I like this. But if the caller is already throwing the Exception, this exception would be muted right? For e.g. I have seen NumberFormatException not handled because the caller already throws the Exception.So, is there a corollary rule - a method should never throw the "Exception" itself?
srini.venigalla
I am of the opinion that if the element cannot be found, the caller shouldn't have called the method from the start at all. You could have a check method, so you can write if(hasElement('test')) getMandatoryChildElement('test');. Much better than the try-catch-try next method sort of code. How would you write a 'load file' method?
disown
@disown : the problem is giving a method in an API. You don't know the user, so you have to make sure he won't be doing bad things, and tell him when he's doing [email protected] : if the caller already throws Exception, he's gonna catch it somewhere sooner or later.
Valentin Rocher
@disown: Another aspect to this approach is that the fewer branches in your code (i.e. if statements) the easier it is to test. Check my answer here for more information: http://stackoverflow.com/questions/1274792/is-returning-null-bad-design/1274822#1274822.
Adamski
@Adamski, Valentin: I agree with that there should be an error, I was just arguing that the MissingElementException should be a runtime exception. If you include the error check in the normal flow, you get one more branch anyway. You usually need to handle the exceptional case anyway, the question is just how you approach it: Reactively or proactively. I prefer proactively.
disown
@disown : Can't disagree more. Looking up a node with xpath for example is quite expensive. I don't' want to do it twice to get the value. I'd rather have an exception thrown on the rare cases that it's not there.
Chris Nava
+1  A: 

It really depends on how you want that situation to be handled. If it is truly an error condition then throw an exception. If null is an acceptable output then merely document it and let the user handle it.

Poindexter
+5  A: 

If null is an acceptable return value (ie, it can result from valid inputs rather than an error case) then return null; otherwise throw an exception.

I don't at all understand your statement that a checked exception may be a bad idea because the caller is forced to handle them - this is the whole point of checked exceptions. It guards against error conditions propagating into the code without being handled properly.

danben
@danben - I really dislike an API that throws half a dozen custom exceptions and I have to add a stack of irrelevant exception handlers. That itself is not a problem, but if the API adds a new exception, all the upstream chain needs to be updated. I can understand all that is necessary or even a good thing, but I was looking for clear conventions to follow.
srini.venigalla
@srini.venigalla - a half dozen is generally too many. Keep in mind there is no reason to necessarily to have ANY **custom** exceptions - you can throw `IllegalArgumentException` or something else that fits your needs.
danben
What is the benefit of having a custom checked exception like AxisException or SoapException or WhateverException? All you can deduce from this is that the exception came from the lib, which you knew anyway from the stacktrace. If you want to do catch-all error handling, it's easily added in the client.
disown
@disown: nobody is disputing that... There's not much point. Also some will dispute the very concept of checked exceptions altogether and there are certainly very successful languages that are doing perfectly fine and that will continue to do perfectly fine without them. Some even view checked exceptions as glorified GOTO statements so it is for sure a debatable topic.
Webinator
I would also add, that if the API allows me to set a value to null, then it should darn well be a null when I get it. Throwing an exception in this scenario would be very inconsistent.
Robin
@danben: I think the exact opposite :-) If `null` is an acceptable return value, then the only way to distinguish between an invalid input and a valid input resulting in `null` is to throw an exception.
Eli Acherkan
@Eli Acherkan: you can read that as "if `null` is an acceptable return value in an error case".
danben
+1  A: 

If you have internal library errors (unexpected), let the runtime exceptions propagate. If there is a bug in the library code, the client is expected to crash. Fix the bug in the library. Don't catch all and return a library-specific exception, this won't do any good.

If you expect things to (sometimes) go wrong, build this into the API. This is based on the principle that you shouldn't use exceptions for normal program flow.

For instance:

ProcessResult performLibraryTask(TaskSpecification ts)

This way you can have ProcessResult indicate error conditions:

ProcessResult result = performLibraryTask(new FindSmurfsTaskSpecification(SmurfColor.BLUE));
if (result.failed()) {
    throw new RuntimeException(result.error());
}

This approach is similar to the return null approach, but you can send more information back to the client.

EDIT:

For interaction which doesn't conform to the agreed protocol, you can throw runtime errors, which you can document. For instance:

if (currentPeriod().equals(SmurfColor.BLUE) && SmurfColor.GREEN.equals(taskSpecification.getSmurfColor()) {
    throw new IllegalStateException("Cannot search for green smurfs during blue period, invalid request");
}

Please note that this is due to an interaction which breached the contract, and is not expected to happen.

disown
I like it, but this approach like the null return, begs for the caller's mercy.
srini.venigalla
Agreed. You will have to set a limit for which errors you consider likely to happen during normal use, and model these as non-exceptions. Coding errors (breach of contract) or things which you don't see happening during normal use (like out of memory, null pointer dereferencing), you should use exceptions for.
disown
+2  A: 

I tend to return null to "getXXX" methods that, for example, fetch something from the database example : User getUserByName(String name) is OK for me to return null

But, if you NEED what you are fetching by calling the method, throw an exception : ex : getDatabaseConnection() must always return a connection, and never return null

And, for methods that return a collection or an array, NEVER return null. return an empty collection/array instead

chburd
I usually use findXXX for methods which can return null, and getXXX for those who won't.
disown
@disown - that would be nonstandard and disallow the usage of java bean libraries and code.
Robin
@Robin: If you are writing a database API? Javabeans are for simple DTO type classes. You aren't seriously naming all your methods according to the java beans spec?
disown
@disown - Of course not. My bad though for jumping around reading several answers and comments (not necessarily in order). Thus I didn't associate your comment to the example in this answer. My apologies.
Robin
+1  A: 

A agree with the others, if null is an acceptable return value, return it, but otherwise not.

What I would like to add, is that you can also distinguish between checked and unchecked exceptions. In some cases it may be advisable to use unchecked exception, e.g. the user of your API is probably not in the situation to deal with that exception anyways. Spring Framework uses unchecked Exceptions very often, which makes the code often easier to read, but its harder to track down errors sometimes.

Nils Schmidt
+4  A: 

Josh Bloch recommends returning empty objects or "unit" objects in place of null values. Check out Effective Java for a ton of useful Java tidbits.

kgrad
+1  A: 

In Practial API Design, the author advises to not return null value (see p.24).

His main point is that it leads to the proliferation of checks against null value and more documentation.

I also strongly recommend reading "Null References: The Billion Dollar Mistake" by an authority in the field (T. Hoare).

ewernli
+1 to you - If only someone can put a value around the time spent on fixing null problems and memcpy problems..
srini.venigalla
*billion dollar :P
Jeriko
@Jeriko you're right. fixed.
ewernli
+2  A: 

My point is that

Never ever return NULL when return type is collection or an array. If no return value , then return an empty collection or an empty array.

This eliminates the need for null check.

Good practice:

public List<String> getStudentList()
{
     int count = getStudetCount();
     List<String> studentList = new ArrayList<String>(count);
     //Populate studentList logic
     return studentList;
}

Bad Practice:. Never ever write the code like below.

public List<String> getStudentList()
{
     int count = getStudetCount();
     if(count == 0)
     {
         return null;
     }
     //Populate studentList logic
     return studentList;
}
Sreejesh
If the `studentList` is supposed to be immutable: you would be better off checking the `count` returned by `getStudentCount()` and then using `Collections.emptyList()` if it was 0. This allows for a potential optimization (i.e. having a cached empty list that is returned each time). If the `count` was not 0, you should still wrap the returned list in a `Collections.unmodifiableList(studentList)` wrapper to ensure it's not accidentally modified.
cdmckay