Throwing Exceptions

What are best practices for throwing exceptions?

Use Exceptions only for exceptional Conditions

A programmer must not be forced by an API to catch an exception to get information about the state of the service s/he is using. S/he should never use exceptions to do clever tricks.

Joshua Bloch states it like this:

[E]xceptions are, as their name implies, to be used only for exceptional conditions; they should never be used for ordinary flow control. [...] A well-designed API must not force it clients to use exceptions for ordinary flow control. Effective Java, p. 242

For example the Iterator provides a method hasNext() to check if there are further elements to iterate over. There is no need to check for the NoSuchElementException when calling next().

Know Common Exceptions for Reuse

There are some basic exceptions that are often used, especially for precondition checks. This table is based on Effective Java, p. 249

Exception Occasion to Use
IllegalArgumentException This is the classical precondition check to validate non-null input arguments.
NullPointerException Also a precondition check that an argument is not null. It is also used if a method returns a null value which is not expected.
IllegalStateException The state of the object is invalid prior to the invocation of a method. This problem may either be temporary or final without a cure.
IndexOutOfBoundsException An index parameter is out of the acceptable range.

Failure Atomicity

Throwing an exception should keep the object in the state it was prior to the method call. This is not an issue for errors.

This is archived by the following

  • Check the input arguments and fail on any violation of preconditions.
  • Make no change to the internal state until you are sure the operation has run successfully. Then change the state with the calculated values.
  • If you cannot run the method without changing the state consider
    1. running the operation on a clone.
    2. providing recover code that corrects the changes already made on failure.

Never fail in Finally Block

Make sure to not throw an exception in the finally block. If you throw an exception in the finally block, the caught exception gets lost.

Preserve Stack Trace

The stack trace provides valuable information about where a problem is located. When re-throwing an exception make sure to preserve this stack trace by exception changing unless you have proper reason to use exception translation.

If the exception you want to throw does not allow to add an exception as cause, use tip Exception with no Cause.