Trail: Essential Java Classes
|
Lesson: Handling Errors with 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 PrintWriter. 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:
-
The
new FileWriter statement failed and threw an IOException.
-
The
victor.elementAt(i) statement failed and threw an ArrayIndexOutOfBoundsException.
-
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 PrintWriter.
finally {
if (out != null) {
System.out.println("Closing PrintWriter");
out.close();
} else {
System.out.println("PrintWriter 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 PrintWriter 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 PrintWriter 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 PrintWriter at the end of the try
block and again within the exception handler for ArrayIndexOutOfBoundsException,
as shown here:
try {
. . .
out.close(); // don't do this; it duplicates code
} catch (ArrayIndexOutOfBoundsException e) {
out.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 PrintWriter within the new
exception handler (which if you're anything like me, you are bound to forget).
|