Trail: Essential Java Classes
|
Lesson: Handling Errors with Exceptions
|
|
Putting It All Together
The previous sections describe how to construct the try,
catch, and finally code blocks for
the writeList example. Now, let's walk through the
code and investigate what happens during three scenarios.
When all of the components are put together, the writeList
method looks like this:
public void writeList() {
PrintWriter out = null;
try {
System.out.println("Entering try statement");
out = new PrintWriter(
new FileWriter("OutFile.txt"));
for (int i = 0; i < size; i++)
out.println("Value at: " + i + " = " + victor.elementAt(i));
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Caught ArrayIndexOutOfBoundsException: " +
e.getMessage());
} catch (IOException e) {
System.err.println("Caught IOException: " + e.getMessage());
} finally {
if (out != null) {
System.out.println("Closing PrintWriter");
out.close();
} else {
System.out.println("PrintWriter not open");
}
}
}
This try block in this method has three different exit possibilities:
-
The
new FileWriter statement fails and throws an IOException.
-
The
victor.elementAt(i) statement fails and throws an ArrayIndexOutOfBoundsException.
-
Everything succeeds and the
try statement exits normally.
This section investigates in
detail what happens in the writeList method during
each of those exit possibilities.
Scenario 1: An IOException Occurs
The new FileWriter("OutFile.txt") statement can fail for
any number of reasons: the user doesn't have write permission on the file or
directory, the file system is full, or the directory for the file doesn't exist.
If any of these situations is true, then the constructor for FileWriter
throws an IOException.
When the IOException is thrown, the runtime system immediately stops execution
of the try block. Then the runtime system attempts to locate an
exception handler appropriate for handling an IOException.
The runtime system begins its search at
the top of the method call stack. When the exception occurred, the FileWriter
constructor was at the top of the call stack. However, the FileWriter
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.
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 FileWriter constructor
is also an IOException and can be legally 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
After the exception handler has run, the runtime system passes control to the
finally block. In this particular scenario, the PrintWriter never
was opened, and thus out is null and won't get closed.
After the finally block has completed executing, the program
continues with the first statement after the finally block.
The complete output that you see from the ListOfNumbers program when an IOException
is thrown is this:
Entering try statement
Caught IOException: OutFile.txt
PrintWriter not open
Scenario 2: An ArrayIndexOutofBoundsException Occurs
This scenario is the same as the first except that a different error occurs
during the try block. In this scenario, the argument passed to
the Vector's elementAt method is out of bounds. That is, the
argument is either less than 0 or is larger than the size of the array.
(The way the code is written, this is actually impossible, but let's suppose
a bug is introduced into the code when someone modifies it.)
As in to scenario 1, when the exception occurs the runtime system stops
execution of the try block and attempts to locate an exception
handler suitable for an ArrayIndexOutofBoundsException. The runtime system
searches for an appropriate exception handler as it did before. It comes
upon the catch statement in the writeList method
that handles exceptions of the type ArrayIndexOutofBoundsException. Since
the type of the thrown exception matches the type of the exception handler,
the runtime system executes this exception handler.
After the exception handler has run, the runtime system passes control to the
finally block. In this particular scenario, the PrintWriter did get
opened, thus the finally statement closes it.
After the finally block has completed executing, the program
continues with the first statement after the finally block.
The complete output that you see from the ListOfNumbers program when an
ArrayIndexOutofBoundsException is thrown is something like this:
Entering try statement
Caught ArrayIndexOutOfBoundsException: 10 >= 10
Closing PrintWriter
Scenario 3: The try block exits normally
In this scenario, all the statements within the scope of the try
block execute successfully and throw no exceptions. Execution falls off the
end of the try block, and then the runtime system passes control to
the finally block. Since everything was successful,
the PrintWriter is open when control reaches the finally block,
which closes the PrintWriter.
Again, after the finally block has completed executing, the program
continues with the first statement after the finally block.
Thus, the output that you see from the ListOfNumbers program when
no exceptions are thrown is:
Entering try statement
Closing PrintWriter
|