Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Exceptional practices, Part 2

Use exception chaining to preserve debugging information

  • Print
  • Feedback
In Part 1 of this series, I looked at some general concepts surrounding sensible exception use in Java programs. In this article, I focus in greater depth on a particular exception-handling technique called exception chaining (sometimes called exception wrapping), which illustrates the principles laid out in Part 1. Exception chaining allows you to map one exception type to another, so that a method can throw exceptions defined at the same abstraction level as the method itself, without discarding important debugging information.

Read the whole series on exception handling:



What's in an exception?

An exception carries three important pieces of information:

  1. The type of exception -- the exception class
  2. Where the exception occurred -- the stack trace
  3. Context and explanatory information -- the error message, and other state information


Each item is relevant to a different party. Software entities care about the exception class -- the JVM and the code that calls the throwing method use it to determine how to handle the exception. The other two items are relevant to people -- a developer or support engineer analyzes the stack trace to debug the problem, and a user or developer examines the error message. Each party must receive the information it needs to effectively deal with the error.

A first attempt at wrapping exceptions

To ensure that the first of these characteristics -- the exception class -- is as useful as possible, it is a common technique for a method to catch one type of exception and immediately rethrow another type. As an example of this technique, consider the ResourceLoader class below, which a program might use to load a resource such as a graphic or audio file. This implementation of loadResource() fetches the resource from a database, but nothing in ResourceLoader's specification requires that -- the resource could come from a file or a remote server.

public class ResourceLoader { 
  public loadResource(String resourceName) throws ResourceLoadException {
    Resource r;
    try {
      r = loadResourceFromDB(resourceName);
    }
    catch (SQLException e) {
      throw new ResourceLoadException("SQL Exception loading resource " 
                                      + resourceName: " + e.toString());
    }
  }
}


loadResource's implementation uses exceptions reasonably well. By throwing ResourceLoadException instead of SQLException (or whatever other exceptions the implementation throws), loadResource hides the implementation from the caller, making it easier to change the implementation without modifying calling code. Additionally, the exception thrown by loadResource() -- ResourceLoadException -- relates directly to the task it performs: loading a resource. The low-level exceptions SQLException and IOException don't directly relate to the task this method performs, and therefore will likely prove less useful to the caller. Further, this wrapping preserves the original exception's error message so the user knows why the resource could not load (perhaps because of a connection error or an incorrect username or password) and can take corrective action.

  • Print
  • Feedback

Resources