Jan. 2, 2005, 1:59 a.m.

When to return null and when to throw an Exception?

I am pretty sure once you transcend the youth phase of software development, and you start thinking about what you are actually doing whilst writing code, you'll start running into tough decisions such as when to throw an exception, and when to return null.

I found a simple way of resolving this controversy. Before answering that question, you need to ask yourself "Would it be beneficial to the caller if the code throws an exception or would it be more beneficial if I return null". This refers both to the code and the programmer. I say this since returning null is generally regarded as a Bad Thing, since the onus is on the developer to ensure the return result is checked. However, there are scenarios in which it is better to return null.

Lets focus for a moment on framework design. This is a bit different since many people will be using your code and be absolutely dependent on the way you return from the function call, whilst writing application code you normally tend not to invoke a method that regularly, thus if you made a mistake it should not be that terrible.

Consider the following piece of code in pseudo language:

function newestDate(Date Date1, Date Date2) returns Date
  if Date1 is null or Date2 is null
    return null   

  if Date1 before Date2
    return Date2
    return Date1
end function

This method returns null on invalid input. Some developers call this technique GIGO (Garbage In Garbage Out). While in principle this might seem attractive and simple - i.e. you do not end up with anything worse than you had, it is not a good thing to do in this case. I say this because of the intent of the method newestDate(). This method evaluates which of the two dates are the newest. Possible return values are (ignoring the case where Date1 == Date2):

The first two return values are trivial. It is the last one that deserves some careful thought. There are four ways to return from the function if the third return value holds, namely:

All of these are valid assumptions - none of them are fundamentally wrong. It is merely a matter of choosing the best one for the intent of the specific function. The benefit of returning null is simplicity - the caller does not have to catch the exception if this is an expected (i.e. normal) condition - the code flow is thus neater. The con is that the onus is on the developer to ensure the null return value is not used anywhere, and checked on return of this method. If this is not done, it may be difficult to determine the cause of the NullPointerException error that is bound to happen. Returning null is thus a tradeoff between simplistic code flow versus developer responsibility. Throwing an exception is exactly the opposite. A benefit is that if the developer does not think about this scenario it will not be difficult to troubleshoot since the exception will be propagated up the call stack with a detailed error message. The con is that if this is an expected condition, it is more work to catch the exception every time and handle it.

I personally prefer the exception - rather let the developer work a little bit harder when a scenario such as this occurs, so that handling of a null date can be coded for properly. If the developer is lazy and we made use of a RuntimeException, at least it will take only a blink of the eye to pinpoint the source of the problem. However if we returned null, the onus is on the developer to RTFM and ensure the return date is checked properly. Since developers do not read manuals, this is a bad assumption to make.

In another example, consider this:

function toIntegerArray(Object[] pArray) returns Integer[] 
  if pArray is null
    return null

  // Build array

  return vArray
end function

Here I opted to return null since converting a null array to an integer array, is still a null array. This is mathematically correct. Throwing an exception would not really be justifyable here.

The decision to return null or to throw an exception is not trivial to make, but as a rule of thumb use this solution: If in doubt, throw an exception. Only if you are absolutely confident it makes mathematical sense to return null, proceed.