System, but they may not be reproduced for publication



Yüklə 83 Mb.
Pdf görüntüsü
səhifə44/82
tarix19.04.2023
ölçüsü83 Mb.
#106251
1   ...   40   41   42   43   44   45   46   47   ...   82
Java A Beginner’s Guide, Eighth Edition ( PDFDrive )

NOTE
There is another form of the try statement that supports automatic resource
management. This form of try is called try­with­resources. It is described in 
Chapter
10
, in the context of managing I/O streams (such as those connected to a file) because
streams are some of the most commonly used resources.
A Simple Exception Example
Here is a simple example that illustrates how to watch for and catch an exception. As
you know, it is an error to attempt to index an array beyond its boundaries. When this
occurs, the JVM throws an ArrayIndexOutOfBoundsException. The following
program purposely generates such an exception and then catches it:
This program displays the following output:
Although quite short, the preceding program illustrates several key points about
exception handling. First, the code that you want to monitor for errors is contained
within a try block. Second, when an exception occurs (in this case, because of the
attempt to index nums beyond its bounds), the exception is thrown out of the try
block and caught by the catch statement. At this point, control passes to the catch,
and the try block is terminated. That is, catch is not called. Rather, program execution


is transferred to it. Thus, the println( ) statement following the out­of­bounds index
will never execute. After the catch statement executes, program control continues with
the statements following the catch. Thus, it is the job of your exception handler to
remedy the problem that caused the exception so that program execution can continue
normally.
Remember, if no exception is thrown by a try block, no catch statements will be
executed and program control resumes after the catch statement. To confirm this, in
the preceding program, change the line
to
Now, no exception is generated, and the catch block is not executed.
It is important to understand that all code within a try block is monitored for
exceptions. This includes exceptions that might be generated by a method called from
within the try block. An exception thrown by a method called from within a try block
can be caught by the catch statements associated with that try block—assuming, of
course, that the method did not catch the exception itself. For example, this is a valid
program:


This program produces the following output, which is the same as that produced by the
first version of the program shown earlier:
Since genException( ) is called from within a try block, the exception that it
generates (and does not catch) is caught by the catch in main( ). Understand,
however, that if genException( ) had caught the exception itself, it never would have
been passed back to main( ).
THE CONSEQUENCES OF AN UNCAUGHT
EXCEPTION
Catching one of Java’s standard exceptions, as the preceding program does, has a side
benefit: It prevents abnormal program termination. When an exception is thrown, it
must be caught by some piece of code, somewhere. In general, if your program does not
catch an exception, then it will be caught by the JVM. The trouble is that the JVM’s
default exception handler terminates execution and displays a stack trace and error


message. For example, in this version of the preceding example, the index out­of­
bounds exception is not caught by the program.
When the array index error occurs, execution is halted, and the following error message
is displayed. (The exact output you see may vary because of differences between JDKs.)
While such a message is useful for you while debugging, it would not be something that
you would want others to see, to say the least! This is why it is important for your
program to handle exceptions itself, rather than rely upon the JVM.
As mentioned earlier, the type of the exception must match the type specified in a
catch statement. If it doesn’t, the exception won’t be caught. For example, the
following program tries to catch an array boundary error with a catch statement for an
ArithmeticException (another of Java’s built­in exceptions). When the array
boundary is overrun, an ArrayIndexOutOfBoundsException is generated, but it
won’t be caught by the catch statement. This results in abnormal program termination.


The output is shown here. (Again, your output may vary based on differences between
JDKs.)
As the output demonstrates, a catch for ArithmeticException won’t catch an
ArrayIndexOutOfBoundsException.
Exceptions Enable You to Handle Errors Gracefully
One of the key benefits of exception handling is that it enables your program to respond
to an error and then continue running. For example, consider the following example
that divides the elements of one array by the elements of another. If a division by zero
occurs, an ArithmeticException is generated. In the program, this exception is
handled by reporting the error and then continuing with execution. Thus, attempting to
divide by zero does not cause an abrupt run­time error resulting in the termination of
the program. Instead, it is handled gracefully, allowing program execution to continue.


The output from the program is shown here:
This example makes another important point: Once an exception has been handled, it
is removed from the system. Therefore, in the program, each pass through the loop
enters the try block anew; any prior exceptions have been handled. This enables your
program to handle repeated errors.
USING MULTIPLE CATCH STATEMENTS
As stated earlier, you can associate more than one catch statement with a try. In fact,
it is common to do so. However, each catch must catch a different type of exception.
For example, the program shown here catches both array boundary and divide­by­zero
errors:


This program produces the following output:
As the output confirms, each catch statement responds only to its own type of
exception.
In general, catch expressions are checked in the order in which they occur in a
program. Only a matching statement is executed. All other catch blocks are ignored.
CATCHING SUBCLASS EXCEPTIONS
There is one important point about multiple catch statements that relates to
subclasses. A catch clause for a superclass will also match any of its subclasses. For
example, since the superclass of all exceptions is Throwable, to catch all possible


exceptions, catch Throwable. If you want to catch exceptions of both a superclass type
and a subclass type, put the subclass first in the catch sequence. If you don’t, then the
superclass catch will also catch all derived classes. This rule is self­enforcing because
putting the superclass first causes unreachable code to be created, since the subclass
catch clause can never execute. In Java, unreachable code is an error.
For example, consider the following program:
The output from the program is shown here:
Ask the Expert
Q
: Why would I want to catch superclass exceptions?


A
: There are, of course, a variety of reasons. Here are a couple. First, if you add a
catch clause that catches exceptions of type Exception, then you have effectively
added a “catch all” clause to your exception handler that deals with all program­
related exceptions. Such a “catch all” clause might be useful in a situation in which
abnormal program termination must be avoided no matter what occurs. Second, in
some situations, an entire category of exceptions can be handled by the same
clause. Catching the superclass of these exceptions allows you to handle all without
duplicated code.
In this case, catch(Throwable) catches all exceptions except for
ArrayIndexOutOfBounds­Exception. The issue of catching subclass exceptions
becomes more important when you create exceptions of your own.
TRY BLOCKS CAN BE NESTED
One try block can be nested within another. An exception generated within the inner
try block that is not caught by a catch associated with that try is propagated to the
outer try block. For example, here the ArrayIndexOutOfBoundsException is not
caught by the inner catch, but by the outer catch:


The output from the program is shown here:
In this example, an exception that can be handled by the inner try—in this case, a
divide­by­zero error—allows the program to continue. However, an array boundary
error is caught by the outer try, which causes the program to terminate.
Although certainly not the only reason for nested try statements, the preceding
program makes an important point that can be generalized. Often nested try blocks are
used to allow different categories of errors to be handled in different ways. Some types


of errors are catastrophic and cannot be fixed. Some are minor and can be handled
immediately. You might use an outer try block to catch the most severe errors, allowing
inner try blocks to handle less serious ones.
THROWING AN EXCEPTION
The preceding examples have been catching exceptions generated automatically by the
JVM. However, it is possible to manually throw an exception by using the throw
statement. Its general form is shown here:
throw exceptOb;
Here, exceptOb must be an object of an exception class derived from Throwable.
Here is an example that illustrates the throw statement by manually throwing an
ArithmeticException:
The output from the program is shown here:
Notice how the ArithmeticException was created using new in the throw
statement. Remember, throw throws an object. Thus, you must create an object for it
to throw. That is, you can’t just throw a type.
Rethrowing an Exception


An exception caught by one catch statement can be rethrown so that it can be caught
by an outer catch. The most likely reason for rethrowing this way is to allow multiple
handlers access to the exception. For example, perhaps one exception handler manages
one aspect of an exception, and a second handler copes with another aspect.
Remember, when you rethrow an exception, it will not be recaught by the same catch
statement. It will propagate to the next catch statement. The following program
illustrates rethrowing an exception:
Ask the Expert
Q
: Why would I want to manually throw an exception?
A
: Most often, the exceptions that you will throw will be instances of exception
classes that you created. As you will see later in this chapter, creating your own
exception classes allows you to handle errors in your code as part of your
program’s overall exception handling strategy.


In this program, divide­by­zero errors are handled locally, by genException( ), but an
array boundary error is rethrown. In this case, it is caught by main( ).
A CLOSER LOOK AT THROWABLE
Up to this point, we have been catching exceptions, but we haven’t been doing anything
with the exception object itself. As the preceding examples all show, a catch clause
specifies an exception type and a parameter. The parameter receives the exception
object. Since all exceptions are subclasses of Throwable, all exceptions support the
methods defined by Throwable. Several commonly used ones are shown in 
Table 9­1
.


Table 9­1 Commonly Used Methods Defined by Throwable
Of the methods defined by Throwable, two of the most interesting are
printStackTrace( ) and toString( ). You can display the standard error message
plus a record of the method calls that lead up to the exception by calling
printStackTrace( ). You can use toString( ) to retrieve the standard error message.
The toString( ) method is also called when an exception is used as an argument to
println( ). The following program demonstrates these methods:


The output from this program is shown here. (Your output may vary because of
differences between JDKs.)
USING FINALLY
Sometimes you will want to define a block of code that will execute when a try/catch


block is left. For example, an exception might cause an error that terminates the
current method, causing its premature return. However, that method may have opened
a file or a network connection that needs to be closed. Such types of circumstances are
common in programming, and Java provides a convenient way to handle them: finally.
To specify a block of code to execute when a try/catch block is exited, include a
finally block at the end of a try/catch sequence. The general form of a try/catch that
includes finally is shown here.
try {
// block of code to monitor for errors
}
catch (ExcepType1 exOb) {
// handler for ExcepType1
}
catch (ExcepType2 exOb) {
// handler for ExcepType2
}
//...
finally {
// finally code
}
The finally block will be executed whenever execution leaves a try/catch block, no
matter what conditions cause it. That is, whether the try block ends normally, or
because of an exception, the last code executed is that defined by finally. The finally
block is also executed if any code within the try block or any of its catch statements
return from the method.
Here is an example of finally:


Here is the output produced by the program:


As the output shows, no matter how the try block is exited, the finally block is
executed.
USING THROWS
In some cases, if a method generates an exception that it does not handle, it must
declare that exception in a throws clause. Here is the general form of a method that
includes a throws clause:

Yüklə 83 Mb.

Dostları ilə paylaş:
1   ...   40   41   42   43   44   45   46   47   ...   82




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©genderi.org 2024
rəhbərliyinə müraciət

    Ana səhifə