Exception Handling Policy – Throwing Exceptions

An exceptionThis is the first post in a series of four on exception handling.

The series will cover what I think is a good and sound strategy for handling exceptions and errors in your application.

It is written with Java in mind, but is applicable to most languages which feature exceptions.

A quick summary of the coming posts:

  1. Throwing Exceptions (this one)
  2. Using Assertions
  3. Catching Exceptions
  4. Logging Exceptions

Let’s get started!

General

First, we’ll go through some things which apply to all types of exceptions.

Always preserve the stack trace

Make sure that the stack trace of a wrapped exception is captured and preserved. The single worse thing one can do after eating your exceptions is to to capture it but throw away all the essential details.

Be careful with distributed systems, as simplistic use of Java serialization requires the Exception classes be available in all tiers.

Also, pre JDK 1.4 Exceptions do not preserve the stacktrace.

Never use exceptions for flow control

Exceptions are meant for exceptional events – when things go wrong. Don’t build your system based on that something goes wrong.

Also, exceptions are slow, so heavy use of them might lead to performance problems.

Provide enough context

Include information and methods in the exception which help the client deal with the exception.

When defining a new exception don’t just add a new error message, provide enough context for a catcher to gracefully handle the exception. If an existing exception class doesn’t have essential context, create a custom one.

Next, we’ll discuss checked and unchecked exceptions, and when to use them.

Checked exceptions

A checked exception is a Java concept which means an exception which is specified in a method’s signature. It is a way for the designer to tell the client of a method what might go wrong, so that the client can prepare accordingly.

Throw a checked exception if a method can’t fulfill it’s contract

Either that, or don’t promise things you cannot keep.

Make your exceptions part of your contract

Throw an exception which is meaningful in terms of the method’s contract.

Declare unchecked exceptions in the throws clause – make it easy for programmers and the IDE to discover the RuntimeExceptions that may be thrown by your method.

Document exceptions in Javadoc.

Never let implementation-specific exceptions escalate to the higher layers

If the client code cannot do anything about a implementation-specific checked exception, convert it to a unchecked exception.

If you are confident that the business layer can take some recovery action when the implementation-specific exception occurs, convert it into a more meaningful checked exception.

Unchecked exceptions

Unchecked exceptions are all other exceptions, which are “unforeseen”.

Prefer unchecked exceptions for all programming errors

If method parameters are invalid or preconditions not met, throw a unchecked exception. A client shouldn’t add exception handling code for providing invalid parameters, it should provide valid parameters!

Unchecked exceptions have the benefit of not forcing the client API to explicitly deal with them. They propagate to where you want to catch them, or they go all the way out and get reported.

If the client cannot do anything useful, then make the exception unchecked

No sense in forcing the client to handle an exception it does not know how to deal with.

Feel free to provide any comments or thoughts below, and check back in a week for the next episode!