Recasting ecxeptions in Java

There are a few cases where a library method declares that it can throw a particular exception, but as the programmer, you know that you basically never except that exception to occur, and if it did occur, it would be a "serious" condition rather than a run-of-the-mill error. For example, IOExceptions are usually everyday errors that we must handle cleanly, maybe displaying a message to the user asking if they want to retry the operation. Indeed, because something like an IOException is something we reasonably expect to deal with cleanly, the Java compiler actually forces us to handle such an exception when a method declares that it can throw it.

But supposing an IOException occurred while reading an essential configuration file that the application couldn't function without? Or supposing a ClassNotFoundException occurs deserialising a file that we know should contain a String? In this case, there may not be so much that the caller can do to cleanly handle the exception. So instead, we just want to convert the regular IOException into a more "serious" error condition, and not have the caller fuss with handling it.

We can do this with a technique commonly called exception recasting. This is a slightly bad term, because strictly speaking, we're not actually casting an object but creating a new one. The code looks something like this:

public void readConfigFile(File f) {
  try {
    BufferedReader br = new BufferedReader(new FileReader(f));
    try {
      // ...
    } finally {
      br.close();
    }
  } catch (IOException ioe) {
    throw new InternalError("Error reading config file");
  }
}

Our method doesn't declare that it throws any exceptions. To the caller, either the method succeeds, or there's "a serious problem and we should just bomb out". We don't want the caller to have to fuss with catching the exception, because there's really nothing the caller could actually do to remedy the problem. So inside the method, if an IOException occurs, we effectively turn it into a serious InternalError. This is an unchecked exception: we don't need to declare that we throw it, and the caller doesn't need to explicitly handle it. If such an exception occurs, it will be "mopped up" by the uncaught exception handler.

When to use exception recasting

Exception recasting is a powerful technique but open to overuse. On the next page, we examine some cases of when to recast exceptions.