Java Language Java Pitfalls - Exception usage Pitfall - Catching Throwable, Exception, Error or RuntimeException


Example

A common thought pattern for inexperienced Java programmers is that exceptions are "a problem" or "a burden" and the best way to deal with this is catch them all1 as soon as possible. This leads to code like this:

....
try {
    InputStream is = new FileInputStream(fileName);
    // process the input
} catch (Exception ex) {
    System.out.println("Could not open file " + fileName);
}

The above code has a significant flaw. The catch is actually going to catch more exceptions than the programmer is expecting. Suppose that the value of the fileName is null, due to a bug elsewhere in the application. This will cause the FileInputStream constructor to throw a NullPointerException. The handler will catch this, and report to the user:

    Could not open file null

which is unhelpful and confusing. Worse still, suppose that the it was the "process the input" code that threw the unexpected exception (checked or unchecked!). Now the user will get the misleading message for a problem that didn't occur while opening the file, and may not be related to I/O at all.

The root of the problem is that the programmer has coded a handler for Exception. This is almost always a mistake:

  • Catching Exception will catch all checked exceptions, and most unchecked exceptions as well.
  • Catching RuntimeException will catch most unchecked exceptions.
  • Catching Error will catch unchecked exceptions that signal JVM internal errors. These errors are generally not recoverable, and should not be caught.
  • Catching Throwable will catch all possible exceptions.

The problem with catching too broad a set of exceptions is that the handler typically cannot handle all of them appropriately. In the case of the Exception and so on, it is difficult for the programmer to predict what could be caught; i.e. what to expect.

In general, the correct solution is to deal with the exceptions that are thrown. For example, you can catch them and handle them in situ:

try {
    InputStream is = new FileInputStream(fileName);
    // process the input
} catch (FileNotFoundException ex) {
    System.out.println("Could not open file " + fileName);
}

or you can declare them as thrown by the enclosing method.


There are very few situations where catching Exception is appropriate. The only one that arises commonly is something like this:

public static void main(String[] args) {
    try {
        // do stuff
    } catch (Exception ex) {
        System.err.println("Unfortunately an error has occurred. " +
                           "Please report this to X Y Z");
        // Write stacktrace to a log file.
        System.exit(1);
    }
}

Here we genuinely want to deal with all exceptions, so catching Exception (or even Throwable) is correct.


1 - Also known as Pokemon Exception Handling.