Exceptional Exceptions

Thursday, August 27th, 2009

wtf coffeeI’ve heard a lot of mantras regarding how to handle exceptions properly in programming languages that support checked exceptions (eg Java).  Sometimes these mantras are regarded a little too highly, even doing harm in some situations.  I’d like to dissect a couple of these.

Never Sometimes catch the top-level “Exception” class.

There are times when it is definitely appropriate.  Imagine some controller code in a web application.  An underlying system has produced an unexpected exception.  Controller code can’t do anything to fix it, but allowing the exception to continue up the call stack would cause a 500 error.  Catching any thrown exception can allow the Controller to do something better, like output a message to the user notifying them of the error and making a suggestion on what to do next.

In short, catch the top-level Exception class if you know for sure that every thrown exception will be handled more poorly by your caller than you can handle it, and you can’t improve the caller’s behavior.

Always When appropriate catch the most  specific exceptions thrown.

Catching the most specific exceptions thrown is meant to create error handling specific to the problem that was raised.  For example, a “DatabaseConnectionLost” exception would be caught, and in the catch block the connection would be repaired.  It seems reasonable to always want to do this, but in practice, some exceptions are thrown in cases where you can’t do anything about it.  Lets say a method throws “DatabaseConnectionLost” and “DatabaseQueryInvalid”, both of which are children of “DatabaseException.”  In a situation where the calling code can’t repair the connection or fix the query, catching the parent is appropriate, rather than handling each specific case without anything specific to do.  If the code can do something like email the DBA, catching DatabaseException seems useful.

In short, you should always catch the most specific exceptions that you can actually do something about.

Never leave a catch block empty (if you can help it)

This is actually one of those rare never-ism that I’m OK with.  But sadly, when interfacing with poorly thought out code, sometimes you are forced to do this.

Lets say you want to create User objects and add them all to a list, and you know their IDs.  You can get users by ID from a piece of library code that you cannot change.  However, you cannot check if a user ID is valid: there is no method for it.  Further, the getUser method throws UserIdInvalidException when you try to get a user by an invalid ID.  For you, an invalid ID is not an exceptional circumstance, but the library code assumes it is.  Sadly you might be forced to write something like this:

for (id : userIds) {
    try {
        users.add(UserLib.getUser(id));
    }
    catch (UserIdInvalidException e) {
        // If ID is invalid don't include it on the list
    }
}

It is very rare that you actually can’t find a better way.  For the most part, consider a catch block like this to be a mistake unless proven otherwise.

Conclusion

Forget all these “always” and “never” rules.  A rule to live by would read more like this:  Exceptions should always be handled as best they can by the code best suited to handle them.

[Image credit]

1 Comment »

  1. For Java devs. out there I’d add, don’t manually throw an NPE!

    Comment by NBW — September 3, 2009 @ 12:40 pm

RSS feed for comments on this post. TrackBack URI

Leave a comment