AhmadLang / Java, How To Program, 2004
.pdf
robust.
Error-Prevention Tip 13.4
Read the online API documentation for a method before using that method in a program. The documentation specifies the exceptions thrown by the method (if any) and indicates reasons why such exceptions may occur. Then provide for handling those exceptions in your program.
Error-Prevention Tip 13.5
Read the online API documentation for an exception class before writing exception-handling code for that type of exception. The documentation for an exception class typically contains potential reasons that such exceptions occur during program execution.
When line 12 executes, if the denominator is zero, the JVM throws an ArithmethicException object. This object will be caught by the catch block at lines 4247, which displays basic information about the exception by implicitly invoking the exception's toString method, then asks the user to try again.
If the denominator is not zero, method quotient performs the division and returns the result to the point of invocation of method quotient in the try block (line 29). Lines 3031 display the result of the calculation and line 32 sets continueLoop to false. In this case, the try block completes successfully, so the program skips the catch blocks, fails the condition at line 48 and method main completes execution normally.
Note that when quotient throws an ArithmeticException, quotient terminates and does not return a value, and quotient's local variables go out of scope (and the variables are destroyed). If quotient contained local variables that were references to objects and there are no other references to those object, would be marked for garbage collection. Also, when an exception occurs, the try block from which quotient was called terminates before lines 3032 can execute. Here, too, if local variables were created in the try block prior to the exception being thrown, these variables would go out of scope.
If an InputMismatchException is generated by lines 25 or 27, the TRy block terminates and execution continues with the catch block at lines 3441. In this case, method quotient is not called. Then method main continues after the last catch block (line 48).
[Page 648 (continued)]
13.5. When to Use Exception Handling
Exception handling is designed to process synchronous errors, which occur when a statement executes. Common examples we will see throughout the book are out-of-range array indices, arithmetic overflow (i.e., a value outside the representable range of values), division by zero, invalid method parameters, thread interruption and unsuccessful memory allocation (due to lack of memory). Exception handling is not designed to process problems associated with asynchronous events (e.g., disk I/O completions, network message arrivals, mouse clicks and keystrokes), which occur in parallel with, and independent of, the program's flow of control.
Software Engineering Observation 13.2
Incorporate your exception-handling strategy into your system from the design process's inception. Including effective exception handling after a system has been implemented can be difficult.
[Page 649]
Software Engineering Observation 13.3
Exception handling provides a single, uniform technique for processing problems. This helps programmers working on large projects understand each other's error-processing code.
Software Engineering Observation 13.4
Avoid using exception handling as an alternate form of flow of control. These "additional" exceptions can "get in the way" of genuine errortype exceptions.
Software Engineering Observation 13.5
Exception handling simplifies combining software components and enables them to work together effectively by enabling predefined components to communicate problems to application-specific components, which can then process the problems in an applicationspecific manner.
Classes that inherit from class Error are considered to be unchecked. The compiler checks each method call and method declaration to determine whether the method tHRows checked exceptions. If so, the compiler ensures that the checked exception is caught or is declared in a tHRows clause. Recall from Section 13.4 that the tHRows clause specifies the exceptions a method throws. Such exceptions are not caught in the method's body. To satisfy the catch part of the catch-or-declare requirement, the code that generates the exception must be wrapped in a TRy block and must provide a catch handler for the checked-exception type (or one of its superclass types). To satisfy the declare part of the catch-or- declare requirement, the method containing the code that generates the exception must provide a tHRows clause containing the checked-exception type after its parameter list and before its method body. If the catch-or-declare requirement is not satisfied, the compiler will issue an error message indicating that the exception must be caught or declared. This forces programmers to think about the problems that may occur when a method that throws checked exceptions is called. Exception classes are defined to be checked when they are consider important enough to catch or declare.
Software Engineering Observation 13.6
Programmers are forced to deal with checked exceptions. This results in more robust code than would be created if programmers were able to simply ignore the exceptions.
Common Programming Error 13.5
A compilation error occurs if a method explicitly attempts to throw a checked exception (or calls another method that throws a checked exception) and that exception is not listed in that method's tHRows clause.
Common Programming Error 13.6
If a subclass method overrides a superclass method, it is an error for the subclass method to list more exceptions in its tHRows clause than the overridden superclass method does. However, a subclass's throws clause can contain a subset of a superclass's throws list.
[Page 651]
Software Engineering Observation 13.7
If your method calls other methods that explicitly throw checked exceptions, those exceptions must be caught or declared in your method. If an exception can be handled meaningfully in a method, the method should catch the exception rather than declare it.
Unlike checked exceptions, the Java compiler does not check the code to determine whether an unchecked exception is caught or declared. Unchecked exceptions typically can be prevented by proper coding. For example, the unchecked ArithmeticException thrown by method quotient (lines 913) in Fig. 13.2 can be avoided if the method ensures that the denominator is not zero before attempting to perform the division. Unchecked exceptions are not required to be listed in a method's throws clauseeven if they are, it is not required that such exceptions be caught by an application.
Software Engineering Observation 13.8
Although the compiler does not enforce the catch-or-declare requirement for unchecked exceptions, provide appropriate exceptionhandling code when it is known that such exceptions might occur. For example, a program should process the NumberFormatException from
Integer method parseInt, even though NumberFormatException (a subclass of RuntimeException) is an unchecked exception type. This makes your programs more robust.
Various exception classes can be derived from a common superclass. If a catch handler is written to catch exception objects of a superclass type, it can also catch all objects of that class's subclasses. This enables a catch block to handle related errors with a concise notation and allows for polymorphic processing of related exceptions. One could certainly catch each subclass type individually if those exceptions required different processing. Of course, catching related exceptions in one catch block makes sense only if the handling behavior is the same for all subclasses.
If there are multiple catch blocks that match a particular exception type, only the first matching catch block executes when an exception of that type occurs. We stated earlier that it is a compilation error to catch the same type in two different catch blocks associated with a particular try block. This occurs when both types are exactly the same. However, there may be several catch blocks that match an exceptioni.e., several catch blocks whose types are the same as the exception type or a superclass of that type. For instance, we could follow a catch block for type ArithmeticException with a catch block for type Exceptionboth would match ArithmeticExceptions, but only the first matching catch block would execute.
Error-Prevention Tip 13.6
Catching subclass types individually is subject to error if you forget to test for one or more of the subclass types explicitly; catching the superclass guarantees that objects of all subclasses will be caught. Positioning a catch block for the superclass type after all other subclass catch blocks for subclasses of that superclass ensures that all subclass exceptions are eventually caught.
Common Programming Error 13.7
Placing a catch block for a superclass exception type before other catch blocks that catch subclass exception types prevents those blocks from executing, so a compilation error occurs.
[Page 652]
13.7. finally block
Programs that obtain certain types of resources must return them to the system explicitly to avoid socalled resource leaks. In programming languages such as C and C++, the most common kind of resource leak is a memory leak. Java performs automatic garbage collection of memory no longer used by programs, thus avoiding most memory leaks. However, other types of resource leaks can occur. For example, files, database connections and network connections that are not closed properly might not be available for use in other programs.
Error-Prevention Tip 13.7
A subtle issue is that Java does not entirely eliminate memory leaks. Java will not garbage collect an object until there are no more references to it. Thus, memory leaks can occur, if programmers erroneously keep references to unwanted objects.
The finally block (which consists of the finally keyword, followed by code enclosed in curly braces) is optional, and is sometimes referred to as the finally clause. If it is present, it is placed after the last catch block, as in Fig. 13.4:
Java guarantees that a finally block (if one is present in a try statement) will execute whether or not an exception is thrown in the corresponding try block or any of its corresponding catch blocks. Java also guarantees that a finally block (if one is present) will execute if a TRy block exits by using a return, break or continue statement. The finally block will not execute if the application exits early from a try block by calling method System.exit. This method, which we demonstrate in the next chapter, immediately terminates an application.
Figure 13.4. Position of the finally block after the last catch block in a TRy statement.
try
{
statements
resource-acquisition statements
} // end try
catch ( AKindOfException exception1 )
{
exception-handling statements
}// end catch
.
.
.
catch ( AnotherKindOfException exception2 )
{
exception-handling statements
}// end catch
finally
{
statements
resource-release statements
} // end finally
Because a finally block almost always executes, it typically contains resource-release code. Suppose a resource is allocated in a try block. If no exception occurs, the catch blocks are skipped and control proceeds to the finally block, which frees the resource. Control then proceeds to the first statement after the finally block. If an exception does occur in the try block, the program skips the rest of the try block. If the program catches the exception in one of the catch blocks, the program processes the exception, then the finally block releases the resource and control proceeds to the first statement after the finally block.
[Page 653]
Performance Tip 13.2
Always release each resource explicitly and at the earliest possible moment at which the resource is no longer needed. This makes resources immediately available to be reused by your program or by other programs, thus improving resource utilization. Because the finally block is guaranteed to execute whether or not an exception occurs in the corresponding try block, this block is an ideal place to release resources acquired in a TRy block.
Error-Prevention Tip 13.8
A finally block typically contains code to release resources acquired in its corresponding try block; this is an effective way to eliminate resource leaks. For example, the finally block should close any files opened in the TRy block.
If an exception that occurs in a try block cannot be caught by one of that try block's catch handlers, the program skips the rest of the try block and control proceeds to the finally block. Then the program passes the exception to the next outer try blocknormally in the calling methodwhere an associated catch block might catch it. This process can occur through many levels of try blocks.
If a catch block throws an exception, the finally block still executes. Then the exception is passed to the next outer try blockagain, normally in the calling method.
The Java application of Fig. 13.5 demonstrates that the finally block executes even if an exception is not thrown in the corresponding TRy block. The program contains static methods main (lines 719), tHRowException (lines 2245) and doesNotThrowException (lines 4865). Methods tHRowException and doesNotThrowException are declared static, so main can call them directly.
Figure 13.5. try... catch ... finally exception-handling mechanism.
|
|
(This item is displayed on pages 653 - 655 in the print version) |
1 |
// Fig. 13.5: UsingExceptions.java |
|
2 |
// |
Demonstration of the try...catch...finally exception handling |
3 |
// |
mechanism. |
4 |
|
|
5public class UsingExceptions
6{
7public static void main( String args[] )
8{
9try
10{
11throwException(); // call method throwException
12} // end try
13catch ( Exception exception ) // exception thrown by throwException
