Handling Errors using Exceptions |
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 afinally
block.The
try
block of thewriteList()
method that you've been working with opens a PrintStream. The program should close that stream before allowing control to pass out of thewriteList()
method. This poses a somewhat complicated problem becausewriteList()
'stry
block has three different exit possibilities:The runtime system always executes the statements within the
- The
new FileOutputStream
statement failed and threw an IOException.- The
victor.elementAt(i)
statement failed and threw an ArrayIndexOutOfBoundsException.- Everything succeeded and the
try
block exited normally.finally
block regardless of what happens within thetry
block. That is, regardless of whether control exits thewriteList()
method'stry
block due to scenario 1, 2, or 3 listed above, the code within thefinally
block will be executed.This is the
finally
block for thewriteList()
method which cleans up and closes the PrintStream.finally { if (pStr != null) { System.err.println("Closing PrintStream"); pStr.close(); } else { System.err.println("PrintStream not open"); } }Is the finally Statement Really Necessary?
At first the need for afinally
statement may not be immediately apparent. Programmers often ask "Is thefinally
statement really necessary or is it just sugar for my Java?" In particular, C++ programmers doubt the need for afinally
statement because C++ doesn't have one.The need for a
finally
statement is not apparent until you consider the following: how would the PrintStream in thewriteList()
method get closed if you didn't provide an exception handler for the ArrayIndexOutOfBoundsException and an ArrayIndexOutOfBoundsException occurred? (It would be easy and legal to omit an exception handler for ArrayIndexOutOfBoundsException because it's a runtime exception and the compiler won't alert you that thewriteList()
contains a method call that might throw one.) The answer is that the PrintStream would not get closed if an ArrayIndexOutOfBoundsException occurred andwriteList()
did not provide a handler for it--unless thewriteList()
provided afinally
statement.There are other benefits to using the
finally
statement as well. In thewriteList()
example it is possible to provide for cleanup without the intervention of afinally
statement. For example, you could put the code to close the PrintStream at the end of thetry
block and again within exception handler for ArrayIndexOutOfBoundsException as shown here:However, this duplicates code which makes the code hard to read and prone to errors if you modify the code later. For example, if you add code to thetry { . . . 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()); }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).
Handling Errors using Exceptions |