Handling Errors Using Exceptions |
As you learned on the previous page, thetry
statement defines the scope of its associated exception handlers. You associate exception handlers with atry
statement by providing one or morecatch
blocks directly after thetry
block:There can be no intervening code between the end of thetry { . . . } catch ( . . . ) { . . . } catch ( . . . ) { . . . } . . .try
statement and the beginning of the firstcatch
statement. The general form of Java'scatch
statement is:As you can see, thecatch (SomeThrowableObject variableName) { Java statements }catch
statement requires a single formal argument. The argument to thecatch
statement looks like an argument declaration for a method. The argument type, SomeThrowableObject, 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 fromThrowable
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 later) each call the exception'sgetMessage
method using the exception's declared namee
:You access the instance variables and methods of exceptions in the same manner that you access the instance variables and methods of other objects.e.getMessage()getMessage
is a method provided by theThrowable
class that prints additional information about the error that occurred. TheThrowable
class also implements two methods for filling in and printing the contents of the execution stack when the exception occurred. Subclasses ofThrowable
can add other methods or instance variables. To find out what methods an exception implements, check its class definition and definitions for any of its ancestor classes.The
catch
block contains a series of legal Java statements. These statements are executed if and when the exception handler is invoked. The runtime system invokes the exception handler when the handler is the first one in the call stack whose type matches that of the exception thrown.The
writeList
method from the ListOfNumbers class uses two exception handlers for itstry
statement, with one handler for each of the two types of exceptions that can be thrown within thetry
block --ArrayIndexOutOfBoundsException
andIOException
.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 an IOException occurs within thetry
block. 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, theFileOutputStream
constructor was at the top of the call stack. However, theFileOutputStream
constructor doesn't have an appropriate exception handler so the runtime system checks the next method in the method call stack: thewriteList
method. ThewriteList
method has two exception handlers: one forArrayIndexOutOfBoundsException
and one forIOException
.The runtime system checks
writeList
's handlers in the order that they appear following thetry
statement. The first exception handler whose argument matches that of the thrown exception is the one chosen by the runtime system to handle the exception. (The order of exception handlers matters!) The argument to the first exception handler isArrayIndexOutOfBoundsException
, but the exception that was thrown is anIOException
. AnIOException
cannot legally be assigned to anArrayIndexOutOfBoundsException
, so the runtime system continues its search for an appropriate exception handler.The argument to
writeList
's second exception handler is anIOException
. The exception thrown by theFileOutputStream
constructor is also anIOException
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:The runtime system goes through a similar process if anCaught IOException: OutFile.txtArrayIndexOutOfBoundsException
occurs. For more details, Putting It All Together walks through thewriteList
method after it's been completed (there's one more step) and investigates what happens during three scenarios.Catching Multiple Exception Types with One Handler
The two exception handlers used by thewriteList
method are very specialized. Each handles 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 ofThrowable
or a subclass ofThrowable
. The Java packages contain numerous classes that derive fromThrowable
and thus, build a hierarchy ofThrowable
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 bothIOExceptions
andArrayIndexOutOfBoundsExceptions
. The closest common ancester ofIOException
andArrayIndexOutOfBoundsException
is theException
class. An exception handler that handles both types of exceptions looks like this:Thetry { . . . } catch (Exception e) { System.err.println("Exception caught: " + e.getMessage()); }class is pretty high in the Throwable
class hierarchy. So in addition to theIOException
andArrayIndexOutOfBoundsException
types that this exception handler is intended to catch, it will catch numerous other types. Generally speaking, your exception handlers should be more specialized. 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.
Handling Errors Using Exceptions |