Previous | Next | Trail Map | Writing Java Programs | Handling Errors using Exceptions


The catch Block(s)

As you learned on the previous page, the try statement defines the scope of its associated exception handlers. You associate exception handlers with a try statement by providing one or more sequential catch blocks directly after the try block.
try {
    . . . 
} catch ( . . . ) {
    . . . 
} catch ( . . . ) {
    . . . 
} . . . 
There can be no intervening code between the end of the try statement and the beginning of the first catch statement. The general form of Java's catch statement is:
catch (SomeThrowableClassName variableName) {
    Java statements
}
As you can see, the catch statement requires a single formal argument. The argument to the catch statement looks like an argument declaration for a method. The argument type, SomeThrowableClassName, declares the type of exception that the handler can handle and must be the name of a class that inherits from the Throwable class defined in the java.lang package. (When Java programs throw an exception they are really just throwing an object, and only objects that derive from Throwable can be thrown. You'll learn more about throwing exceptions in How to Throw Exceptions.)

variableName is the name by which the handler can refer to the exception caught by the handler. For example, the exception handlers for the writeList() method (shown below) each call the exception's getMessage() method using the exception's declared name e:

e.getMessage()
You access the instance variables and methods of exceptions in the same manner that you access the instance variables and methods of other objects. getMessage() is a method provided by the Throwable class that prints additional information about the error that occurred. The Throwable class also implements two methods for filling in and printing the contents of the execution stack when the exception occurred. Subclasses of Throwable can add other methods or instance variables. To find out what methods an exception implements check its class and superclass definitions.

The catch statement governs a series of legal Java statements. These statements are executed when and if the exception handler is invoked. The runtime system invokes the exception handler when an exception whose type matches that of the catch statement's argument is thrown within the handler's try block.

The writeList() method from the ListOfNumbers class uses two exception handlers for its try statement--one handler for each of the two different types of exceptions that can be thrown within the try block--ArrayIndexOutOfBoundsException and IOException.

try {
    . . . 
} catch (ArrayIndexOutOfBoundsException e) {
    System.err.println("Caught ArrayIndexOutOfBoundsException: " + e.getMessage());
} catch (IOException e) {
    System.err.println("Caught IOException: " + e.getMessage());
}
An IOException Occurs Let's suppose that the FileOutputStream constructor fails and throws an IOException. The runtime system immediately takes over and tries to locate an appropriate exception handler. The runtime system begins its search at the top of the method call stack. When the exception occurred, the FileOutputStream constructor was at the top of the call stack. However, the FileOutputStream constructor doesn't have an appropriate exception handler so the runtime system checks the next method in the method call stack--the writeList() method. The writeList() method has two exception handlers: one for ArrayIndexOutOfBoundsException and one for IOException.

The runtime system checks writeList's handlers in the order that they appear following the try statement. (So, the order that you write your exception handlers matters!) The argument to the first exception handler is ArrayIndexOutOfBoundsException, but the exception that was thrown is an IOException. An IOException cannot legally be assigned to an ArrayIndexOutOfBoundsException, so the runtime system continues its search for an appropriate exception handler.

The argument to writeList()'s second exception handler is an IOException. The exception thrown by the FileOutputStream constructor is also an IOException and so it can legally be assigned to the handler's IOException argument. Thus, this handler is deemed appropriate and the runtime system executes this handler which prints this statement:

Caught IOException: OutFile.txt
The runtime system goes through a similar process if an ArrayIndexOutOfBoundsException occurs. For more details, Putting It All Together walks through the writeList() method after it's been completed (there's one more step) and investigates what happens during the three possible scenarios that this code presents: the code runs successfully, an IOException occurs, or an ArrayIndexOutOfBoundsException occurs.

Catching Multiple Exception Types with One Handler

The two exception handlers used by the writeList() method are very specialized; they handle only one type of exception. The Java language allows you to write general exception handlers that handle multiple types of exceptions.

As you know, Java exceptions are Throwable objects (they are instances of Throwable or a subclass of Throwable). The Java packages contain numerous classes that derive from Throwable and thus, build a hierarchy of Throwable classes.

Your exception handler can be written to handle any class that inherits from Throwable. If you write a handler for a "leaf" class (a class with no subclasses), you've written a specialized handler: it will only handle exceptions of that specific type. If you write a handler for a "node" class (a class with subclasses), you've written a general handler: it will handle any exception whose type is the node class or any of its subclasses.

Let's modify the writeList() method once again. Only this time, let's write it so that it handles both IOExceptions and ArrayIndexOutOfBoundsExceptions. The closest common ancester of IOException and ArrayIndexOutOfBoundsException is the Exception class. Thus an exception handler that would handle both types of exceptions would look like this:

try {
    . . .
} catch (Exception e) {
    System.err.println("Exception caught: " + e.getMessage());
}
The Exception class is pretty high in the Throwable class hierarchy. So in addition to the IOException and ArrayIndexOutOfBoundsException types that this exception handler is intended to catch, it will also catch numerous other types. Generally speaking, your exception handlers should be more specialized than this one. Handlers that can catch most or all exceptions are typically useless for error recovery because the handler has to determine what type of exception occurred anyway (to determine the best recovery strategy). Also exception handlers that are too general can make code more error prone by catching and handling exceptions that weren't anticipated by the programmer and for which the handler was not intended.


Previous | Next | Trail Map | Writing Java Programs | Handling Errors using Exceptions