Programs that obtain certain types of resources must return them to the system explicitly to avoid so-called 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.
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 5 public class UsingExceptions 6 { 7 public static void main( String args[] ) 8 { 9 try 10 { 11 throwException(); // call method throwException 12 } // end try 13 catch ( Exception exception ) // exception thrown by throwException 14 { 15 System.err.println( "Exception handled in main" ); 16 } // end catch 17 18 doesNotThrowException(); 19 } // end main 20 21 // demonstrate try...catch...finally 22 public static void throwException() throws Exception 23 { 24 try // throw an exception and immediately catch it 25 { 26 System.out.println( "Method throwException" ); 27 throw new Exception(); // generate exception 28 } // end try 29 catch ( Exception exception ) // catch exception thrown in try 30 { 31 System.err.println( 32 "Exception handled in method throwException" ); 33 throw exception; // rethrow for further processing 34 35 // any code here would not be reached 36 37 } // end catch 38 finally // executes regardless of what occurs in try...catch 39 { 40 System.err.println( "Finally executed in throwException" ); 41 } // end finally 42 43 // any code here would not be reached, exception rethrown in catch 44 45 } // end method throwException 46 47 // demonstrate finally when no exception occurs 48 public static void doesNotThrowException() 49 { 50 try // try block does not throw an exception 51 { 52 System.out.println( "Method doesNotThrowException" ); 53 } // end try 54 catch ( Exception exception ) // does not execute 55 { 56 System.err.println( exception ); 57 } // end catch 58 finally // executes regardless of what occurs in try...catch 59 { 60 System.err.println( 61 "Finally executed in doesNotThrowException" ); 62 } // end finally 63 64 System.out.println( "End of method doesNotThrowException" ); 65 } // end method doesNotThrowException 66 } // end class UsingExceptions
|
Before we discuss the flow of control for this example, we would like to point out the use of the System.err to output data (lines 15, 3132, 40, 56 and 6061). By default, System.err.println, like System.out.println, displays data to the command prompt.
Both System.out and System.err are streamsa sequence of bytes. While System.out (known as the standard output stream) is used to display a program's output, System.err (known as the standard error stream) is used to display a program's errors. Output from these streams can be redirected (i.e., sent somewhere other than the command prompt such as a file). Using two different streams enables the programmer to easily separate error messages from other output. For instance, data output from System.err could be sent to a log file, while data output from System.out can be displayed on the screen. For simplicity, this chapter will not redirect output from System.err, but will display such messages to the command prompt. You will learn more about streams in Chapter 14, Files and Streams.
Throwing Exceptions Using the tHRow Statement
Method main (Fig. 13.5) begins executing, enters its try block and immediately calls method tHRowException (line 11). Method throwException tHRows an Exception (line 27), catches it (line 29) and rethrows it (line 33). The statement at line 27 is known as a throw statement. The tHRow statement is executed to indicate that an exception has occurred. So far, you have only caught exceptions thrown by called methods. Programmers can throw exceptions by using the tHRow statement. Just as with exceptions thrown by the Java API's methods, this indicates to client applications that an error has occurred. A tHRow statement specifies an object to be thrown. The operand of a throw can be of any class derived from class Throwable.
Software Engineering Observation 13.9
When toString is invoked on any THRowable object, its resulting string includes the descriptive string that was supplied to the constructor, or simply the class name if no string was supplied. |
Software Engineering Observation 13.10
An object can be thrown without containing information about the problem that occurred. In this case, simple knowledge that an exception of a particular type occurred may provide sufficient information for the handler to process the problem correctly. |
Software Engineering Observation 13.11
Exceptions can be thrown from constructors. When an error is detected in a constructor, an exception should be thrown rather than creating an improperly formed object. |
Rethrowing Exceptions
Line 33 of Fig. 13.5 rethrows the exception. Exceptions are rethrown when a catch block, upon receiving an exception, decides either that it cannot process that exception or that it can only partially process it. Rethrowing an exception defers the exception handling (or perhaps a portion of it) to another catch block associated with an outer TRy statement. An exception is rethrown by using the throw keyword, followed by a reference to the exception object that was just caught. Note that exceptions cannot be rethrown from a finally block, as the exception parameter from the catch block has expired.
When a rethrow occurs, the next enclosing TRy block detects the rethrown exception, and that try block's catch blocks attempt to handle the exception. In this case, the next enclosing TRy block is found at lines 912 in method main. Before the rethrown exception is handled, however, the finally block (lines 3841) executes. Then method main detects the rethrown exception in the try block and handles it in the catch block (lines 1316).
Next, main calls method doesNotThrowException (line 18). No exception is thrown in doesNotThrowException's TRy block (lines 5053), so the program skips the catch block (lines 5457), but the finally block (lines 5862) nevertheless executes. Control proceeds to the statement after the finally block (line 64). Then control returns to main and the program terminates.
Common Programming Error 13.8
If an exception has not been caught when control enters a finally block and the finally block throws an exception that is not caught in the finally block, the first exception will be lost and the exception from the finally block will be returned to the calling method. |
Error-Prevention Tip 13.9
Avoid placing code that can throw an exception in a finally block. If such code is required, enclose the code in a try...catch within the finally block. |
Common Programming Error 13.9
Assuming that an exception thrown from a catch block will be processed by that catch block or any other catch block associated with the same TRy statement can lead to logic errors. |
Good Programming Practice 13.2
Java's exception-handling mechanism is intended to remove error-processing code from the main line of a program's code to improve program clarity. Do not place TRy...catch...finally around every statement that may throw an exception. This makes programs difficult to read. Rather, place one try block around a significant portion of your code, follow that TRy block with catch blocks that handle each possible exception and follow the catch blocks with a single finally block (if one is required). |
Introduction to Computers, the Internet and the World Wide Web
Introduction to Java Applications
Introduction to Classes and Objects
Control Statements: Part I
Control Statements: Part 2
Methods: A Deeper Look
Arrays
Classes and Objects: A Deeper Look
Object-Oriented Programming: Inheritance
Object-Oriented Programming: Polymorphism
GUI Components: Part 1
Graphics and Java 2D™
Exception Handling
Files and Streams
Recursion
Searching and Sorting
Data Structures
Generics
Collections
Introduction to Java Applets
Multimedia: Applets and Applications
GUI Components: Part 2
Multithreading
Networking
Accessing Databases with JDBC
Servlets
JavaServer Pages (JSP)
Formatted Output
Strings, Characters and Regular Expressions
Appendix A. Operator Precedence Chart
Appendix B. ASCII Character Set
Appendix C. Keywords and Reserved Words
Appendix D. Primitive Types
Appendix E. (On CD) Number Systems
Appendix F. (On CD) Unicode®
Appendix G. Using the Java API Documentation
Appendix H. (On CD) Creating Documentation with javadoc
Appendix I. (On CD) Bit Manipulation
Appendix J. (On CD) ATM Case Study Code
Appendix K. (On CD) Labeled break and continue Statements
Appendix L. (On CD) UML 2: Additional Diagram Types
Appendix M. (On CD) Design Patterns
Appendix N. Using the Debugger
Inside Back Cover