Trail: Essential Java Classes
|
Lesson: Handling Errors with Exceptions
|
|
The catch Block(s)
As you learned on the previous page,
the try statement defines the scope of its
associated exception handlers.
You associate exception handlers with a try statement by
providing one or more catch blocks directly
after the try block:
try {
. . .
} catch ( . . . ) {
. . .
} catch ( . . . ) {
. . .
} . . .
There can be no intervening code between the end of the try
statement and the beginning of the first catch statement.
The general form of Java's catch statement is:
catch (SomeThrowableObject variableName) {
Java statements
}
As you can see, the catch statement requires a single formal
argument. The argument to the catch 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 from Throwable 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's
getMessage method using the exception's declared name
e:
e.getMessage()
You access the instance variables and methods of exceptions in the same manner
that you access the instance variables and methods of other objects.
getMessage is a method provided by the Throwable class
that prints additional information about the error that occurred.
The Throwable class also implements two methods for filling in and printing
the contents of the execution stack when the exception occurred.
Subclasses of Throwable 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 its try statement, with one
handler for each of the two types of exceptions that can
be thrown within the try block --
ArrayIndexOutOfBoundsException
and IOException.
try {
. . .
} catch (ArrayIndexOutOfBoundsException e) {
System.err.println("Caught ArrayIndexOutOfBoundsException: " +
e.getMessage());
} catch (IOException e) {
System.err.println("Caught IOException: " +
e.getMessage());
}
Catching Multiple Exception Types with One Handler
The two exception handlers used by the writeList 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
of Throwable or a subclass of Throwable. The Java packages contain
numerous classes that derive from Throwable and thus, build a hierarchy
of Throwable 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 both IOExceptions and ArrayIndexOutOfBoundsExceptions.
The closest common ancester of IOException and ArrayIndexOutOfBoundsException
is the Exception class. An exception handler that handles both
types of exceptions looks like this:
try {
. . .
} catch (Exception e) {
System.err.println("Exception caught: " + e.getMessage());
}
The class is pretty high in the Throwable class hierarchy. So in
addition to the IOException and ArrayIndexOutOfBoundsException 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.
|