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


The finally Block

The final step in setting up an exception handler is providing a mechanism for cleaning up the state of the method before (possibly) allowing control to be passed to a different part of the program. You do this by enclosing the cleanup code within a finally block.

The try block of the writeList method that you've been working with opens a PrintStream. The program should close that stream before allowing control to pass out of the writeList method. This poses a somewhat complicated problem because writeList's try block has three different exit possibilities:

  1. The new FileOutputStream statement failed and threw an IOException.
  2. The victor.elementAt(i) statement failed and threw an ArrayIndexOutOfBoundsException.
  3. Everything succeeded and the try block exited normally.
The runtime system always executes the statements within the finally block regardless of what happens within the try block. Regardless of whether control exits the writeList method's try block due to one of the three scenarios listed previously, the code within the finally block will be executed.

This is the finally block for the writeList method. It cleans up and closes the PrintStream.

finally {
    if (pStr != null) { 
        System.out.println("Closing PrintStream");
        pStr.close(); 
    } else { 
        System.out.println("PrintStream not open");
    } 
} 

Is the finally Statement Really Necessary?

At first the need for a finally statement may not be immediately apparent. Programmers often ask "Is the finally statement really necessary or is it just sugar for my Java?" In particular, C++ programmers doubt the need for a finally statement because C++ doesn't have one.

The need for a finally statement is not apparent until you consider the following: how does the PrintStream in the writeList method get closed if you don't provide an exception handler for the ArrayIndexOutOfBoundsException and an ArrayIndexOutOfBoundsException occurs? (It's easy and legal to omit an exception handler for ArrayIndexOutOfBoundsException because it's a runtime exception and the compiler won't alert you that the writeList contains a method call that might throw one.) The answer is that the PrintStream does not get closed if an ArrayIndexOutOfBoundsException occurs and writeList does not provide a handler for it--unless the writeList provides a finally statement.

There are other benefits to using the finally statement. In the writeList example it is possible to provide for cleanup without the intervention of a finally statement. For example, you could put the code to close the PrintStream at the end of the try block and again within the exception handler for ArrayIndexOutOfBoundsException, as shown here:

try {
    . . .
    pStr.close();       // don't do this; it duplicates code 
} catch (ArrayIndexOutOfBoundsException e) {
    pStr.close();       // don't do this; it duplicates code 
    System.err.println("Caught ArrayIndexOutOfBoundsException: " + e.getMessage());
} catch (IOException e) {
    System.err.println("Caught IOException: " + e.getMessage());
}
However, this duplicates code, making the code hard to read and prone to errors if you modify the code later. For example, if you add code to the try block that may throw a new type of exception, you will have to remember to close the PrintStream within the new exception handler (which if you're anything like me, you are bound to forget).


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