|
The Essence of OOP using Java, Exception Handling By Richard G. Baldwin September 3, 2002 Exceptions that can be thrown within the scope of a method The exceptions that can be thrown within the scope of a method include not only exceptions which are thrown by code written into the method, but also includes exceptions thrown by methods called by that method, or methods called by those methods, etc. According to Campione and Walrath,
Sample programs Now it's time to take a look at some sample code designed to deal with exceptions of the types delivered with the JDK. Initially I won't include exception classes that are designed for custom purposes. However, I will deal with exceptions of those types later in the lesson. The first three sample programs will illustrate the successive stages of dealing with checked exceptions by either catching or declaring those exceptions. Sample program with no exception handling code The first sample program shown in Listing 1 neither catches nor declares the
InterruptedException which can be thrown by the sleep method of
the Thread class.
A possible InterruptedException The code in the main method of Listing 1 invokes the method named myMethod. The method named myMethod invokes the method named sleep of the Thread class. The method named sleep declares that it throws InterruptedException. InterruptedException is a checked exception. The program illustrates the failure to either catch or declare InterruptedException in the method named myMethod. As a result, this program won't compile. The compiler error is similar
to that shown in Figure 3. Note the caret in the last line that points to
the point where the compiler detected the problem.
As you can see, the compiler detected a problem where the sleep method was called, because the method named myMethod failed to deal properly with an exception that can be thrown by the sleep method. Sample program that fixes one compiler error The next version of the program, shown in Listing 2, fixes the problem
identified with the call to the sleep method, by declaring the exception
in the signature for the method named myMethod. The declaration of
the exception of type InterruptedException is highlighted in boldface in
Listing 2.
Another possible InterruptedException As was the case in the previous program, this program also illustrates a failure to catch or declare an InterruptedException. However, in this case, the problem has moved up one level in the call stack relative to the problem with the program in Listing 1. This program also fails to compile, producing a compiler error similar to
that shown in Figure 4. Note that the caret indicates that the problem is
associated with the call to myMethod.
Didn't solve the problem Simply declaring a checked exception doesn't solve the problem. Ultimately, the exception must be handled if the compiler problem is to be solved.
The program in Listing 2 eliminated the compiler error identified with the call to the method named sleep. This was accomplished by declaring that the method named myMethod throws InterruptedException. However, this simply passed the exception up the call stack to the next higher-level method in the stack. This didn't solve the problem, it simply handed it off to another method to solve. The problem still exists, and is now identified with the call to myMethod where it will have to be handled in order to make the compiler error go away. Sample program that fixes the remaining compiler error The version of the program shown in Listing 3 fixes the remaining compiler
error. This program illustrates both declaring and handling a checked
exception. This program compiles and runs successfully.
The solution to the problem This solution to the problem is accomplished by surrounding the call to myMethod with a try block, which is followed immediately by an appropriate catch block. In this case, an appropriate catch block is one whose parameter type is either InterruptedException, or a superclass of InterruptedException.
The myMethod method declares the exception As in the previous version, the method named myMethod (declares the exception and passes it up the call stack to the method from which it was called. The main method handles the exception In the new version shown in Listing 3, the main method provides a try block with an appropriate catch block for dealing with the problem (although it doesn't actually deal with it in any significant way). This can be interpreted as follows:
Not a method call Note that this transfer of control is not a method call. It is an unconditional transfer of control. There is no return from a catch block. Matching catch block was found In this case, there was a matching catch block to receive control. In the event that an InterruptedException is thrown, the program would execute the statement within the body of the catch block, and then transfer control to the code following the final catch block in the group of catch blocks (in this case, there was only one catch block). No output is produced It is unlikely that you will see any output when you run this program, because it is unlikely that an InterruptedException will be thrown. (I didn't provide any code that will cause such an exception to occur.) A sample program that throws an exception Now let's look at the sample program in Listing 4, which throws an exception
and deals with it. This program illustrates the implementation of
exception handling using the try/catch block structure.
Keeping it simple I try to keep my sample programs as simple as possible, introducing the minimum amount of complexity necessary to illustrate the main point of the program. It is easy to write a really simple program that throws an unchecked ArithmeticException. Therefore, the program in Listing 4 was written to throw an ArithmeticException. This was accomplished by trying to perform an integer divide by zero. The try/catch structure is the same ... It is important to note that the try/catch structure illustrated in Listing 4 would be the same whether the exception is checked or unchecked. The main difference is that you are not required by the compiler to handle unchecked exceptions and you are required by the compiler to either handle or declare checked exceptions. Throwing an ArithmeticException The code in Listing 4 executes a simple counting loop inside a try block. During each iteration, the counting loop divides the integer 6 by the value of the counter. When the value of the counter goes to zero, the runtime system tries to perform an integer divide by zero operation, which causes it to throw an ArithmeticException. Transfer control immediately At that point, control is transferred directly to the catch block that follows the try block. This is an appropriate catch block because the type of parameter declared for the catch block is ArithmeticException. It matches the type of the object that is thrown.
Invoking methods inside the catch block Once control enters the catch block, three of the methods of the
Throwable class are invoked to cause information about the situation to be
displayed on the screen. The output produced by the program is similar to
that shown in Figure 5.
Key things to note The key things to note about the program in Listing 5 are:
Doesn't attempt to rectify the problem This program doesn't attempt to show how an actual program might recover from an exception of this sort. However, it is clear that (rather than experiencing automatic and unconditional termination) the program remains in control, and in some cases, recovery might be possible. This sample program illustrates try and catch. The use of finally, will be discussed and illustrated later. A nuisance problem explained While we are at it, I would be remiss in failing to mention a nuisance problem associated with exception handling. As you may recall, the scope of a variable in Java is limited to the block of code in which it is declared. A block is determined by enclosing code within a pair of matching braces: {...}. Since a pair of braces is required to define a try block, the scope of any variables or objects declared inside the try block is limited to the try block. While this is not an insurmountable problem, it may require you to modify your programming style in ways that you find distasteful. In particular, if you need to access a variable both within and outside the try block, you must declare it before entering the try block. The process in more detail Now that you have seen some sample programs to help you visualize the process, lets discuss the process in more detail. The try block According to Campione and Walrath,
Note that the terminology being used by Campione and Walrath treats the catch block as the "exception handler" and treats the try block as something that precedes one or more exception handlers. I don't disagree with their terminology. I mention it only for the purpose of avoiding confusion over terminology. The syntax of a try block The general syntax of a try block, as you saw in the previous program,
has the keyword try followed by one or more statements enclosed in
a pair of matching braces, as shown in Figure 6.
Single statement and multiple exceptions You may have more than one statement that can throw one or more exceptions and you will need to deal with all of them. You could put each such statement that might throw exceptions within its own try block and provide separate exception handlers for each try block.
Thus a try block consisting of a single statement might require many different exception handlers or catch blocks following it. Multiple statements and multiple exceptions You could put all or several of the statements that might throw exceptions within a single try block and associate multiple exception handlers with it. There are a number of practical issues involved here, and only you can decide in any particular instance which approach would be best. The catch blocks must follow the try block However you decide to do it, the exception handlers associated with a try block must be placed immediately following their associated try block. If an exception occurs within the try block, that exception is handled by the appropriate exception handler associated with the try block. If there is no appropriate exception handler associated with the try block, the system attempts to find an appropriate exception handler in the next method up the call stack. A try block must be accompanied by at least one catch block (or one finally block). Otherwise, a compiler error that reads something like 'try' without 'catch' or 'finally' will occur. The catch block(s) Continuing with what Campione and Walrath have to say:
There can be no intervening code between the end of the try block and the beginning of the first catch block, and no intervening code between catch blocks. Syntax of a catch block The general form of a catch block is shown in Figure 7.
The declaration for the catch block requires a single argument as shown. The syntax for the argument declaration is the same as an argument declaration for a method. Argument type specifies type of matching exception object The argument type declares the type of exception object that a particular catch block can handle. The type must be Throwable, or a subclass of the Throwable class discussed earlier. A parameter provides the local name Also, as in a method declaration, there is a parameter, which is the name by which the handler can refer to the exception object. For example, in an earlier program, I used statements such as e.getMessage()to access an instance method of an exception object caught by the exception handler. In that case, the name of the parameter was e. You access the instance variables and methods of exception objects the same way that you access the instance variables and methods of other objects. Proper order of catch blocks According to Campione and Walrath:
Therefore, the order of your exception handlers is very important, particularly if you have some handlers, which are further up the exception hierarchy than others. Those handlers that are designed to handle exception types furthermost from the root of the hierarchy tree (Throwable) should be placed first in the list of exception handlers. Otherwise, an exception handler designed to handle a specific type of object may be preempted by another handler whose exception type is a superclass of that type, if the superclass exception handler appears earlier in the list of exception handlers. Catching multiple exception types with one handler Exception handlers that you write may be more or less specialized. In addition to writing handlers for very specialized exception objects, the Java language allows you to write general exception handlers that handle multiple types of exceptions. Java exceptions are Throwable objects (instances of the Throwable class or a subclass of the Throwable class). The Java standard library contains numerous classes that are subclasses of Throwable and thus build a hierarchy of Throwable classes. According to Campione and Walrath:
|
| Go to page: Prev 1 2 3 Next |
