|
Before we start discussing about the handling of an exception, let us see, what really an exception is. An exception simply means an erroneous condition that may occur during a program execution. When a Java program is executing it may land into situations, which are not quite anticipated in the normal operation of the program. Say for instance, the program is trying to access a file, which is not present on disk or the program runs out of memory and so on. Java uses the term exception to represent such exceptional (not quite normal) circumstances. When such a circumstance actually happens, an exception is said to be thrown. You may write a piece of code that handles these circumstances. Such code is called an exception handler. The process of actually handling the thrown exception is called catching the exception. Java represents the exceptions as objects. The class hierarchy for java.lang.Throwable represents the exception objects.
For handling exceptions programmatically, enclose the statements that might throw an exception within a try block. For instance, if you are trying to open a file, you may face several error conditions. Like, the file itself does not exist or there may be some problem with the I/O device where the file is residing and so on. To handle these conditions, put the file-opening code in a try block and code that deals with these error conditions in respective catch clauses. Listing 5.1 shows a code snippet where the try-catch statement is effectively used to handle error conditions while opening and reading from a file.
![]() |
|
|
Handle the error condition when file hello.txt is not found |
|||
|
|
Handle the error condition when end of file has been reached unexpectedly |
|||
|
|
Handle the error condition when the I/O operation is failed while reading |
The try block is a special region where the code is watched for certain exceptions. Opening a file has a potential of causing an exception. We put such risky code in a try block. Your code may face multiple error conditions while opening a file. Therefore, you can specify multiple catch clauses. Each catch will deal with a specific error condition. The presence of catch clauses does not mean they are executed. When such program runs, and if really an exception occurs, the control is transferred to the matching catch clause and the code in it is executed. For instance, assume that the file hello.txt is present and found. However, an error occurred while reading from the file. The figure 5.1 shows how the control is transferred to the matching catch block.

Figure 5.1 Flow of control when an EOFException occurs in try block.
Let us walk through the code to see how the control moves in this particular scenario. In the try block, a file is opened and the first byte is read. While reading the second byte, the end-of-file is unexpectedly reached and the read operation fails. Java represents this particular file-related exception as EOFException. Therefore, the EOFException is thrown. The try block is terminated and the matching catch clause is found. The control transfers to the catch clause and the handling code inside it is executed. After that, the control is transferred out of try-catch statement and to the first line of code after it.
|
|
The try block is sometimes called a guarded region. This is a section of code that might produce exceptions and is followed by the catch clauses. The catch blocks are called exception handlers as they contain the code that handles exceptions. |
The try block and catch clause
In figure 5.1, we studied one scenario in which the matching catch clause for the exception was present. There can be different scenarios for example, the code may not have a try-catch block at all or may have a try-catch block but no matching catch clause for a particular exception. Table 5.6 summarizes these different scenarios and what happens when a particular exception is thrown by the code at runtime.
Table 5.6 Flow of control in different exception conditions
|
|
About the code |
|
|
|
Exception in code |
The try block |
Matching catch clause for an exception |
What happens? |
|
Is not thrown |
Not present |
Not applicable |
The code is executed normally |
|
Is thrown |
Not present |
Not applicable |
The code terminates abruptly |
|
Is thrown |
Present |
Not found |
The code terminates abruptly |
|
Is thrown |
Present |
Found |
1. Terminates the try block 2. Executes the matching catch clause 3. Executes normally after the try-catch block |
|
Is not thrown |
Present |
Found |
The try block is executed normally. None of the catch clauses is executed. |
Sometimes you need to do some cleanup operations right after the try block. Say, for instance, in our file example, you may want to close the file after you are done reading it. Even if an exception occurs either while opening a file or while reading it, you still want to close it. If you put the code for closing the file at the bottom in try block, it will not execute if an exception occurs within try block. If you decide to put the file-closing code in the catch blocks, you need to do it for every catch block to ensure that the file is closed. Since the catch block to be executed at runtime depends on the exception, you need to write code for file closing in each catch block.. Therefore, you will have a lot of repetition of code, which does the same thing. Java provides you with a finally clause to deal with this problem.
finally clause of try block encloses code which is always executed after the try block. It does not matter if the try block throws any exception. As its name suggests, the finally block is executed finally after a normal execution of a try block. If exception occurs within try block and it has the matching catch block, then the finally clause is executed after that catch clause. If an exception occurred within try block and none of the catch blocks could handle it, still the finally clause is executed after abrupt termination of try. So, the bottom line is that the code in a finally clause is almost certainly executed. Later we will look at some exceptional scenarios in which finally might not execute.
Table 5.7 shows how the finally clause is executed when no exception occurs in a try block as well as when an exception occurs.
Table 5.7 Flow of control in try-catch-finally
|
Exception of type Exception2 is thrown in the try block |
No exception thrown in try block |
|
|
|
The finally clause almost certainly executes. It even executes if there is a return statement within a try block. However, if an exception occurs within the finally clause itself then it will not be executed. The exception in finally behaves just like any other exception and you can handle it with a try-catch within finally. If you don’t, the finally clause will terminate by throwing an exception. If the code in the finally clause has a call to System.exit() it will immediately terminate the program and the remainder of finally clause is never executed.
Declaration rules for a try block and its catch and finally clauses
Now that you have seen, how a try block oversees the execution of enclosed statements for exceptions and how its catch clauses and finally clause are executed, let us discuss some declaration rules for the try block.
The try block must be accompanied by at least one catch clause or one finally clause. A try block without any catch or finally clause is illegal.
If a try block has a catch or finally clause or both, they must follow immediately after the try block. No code should be placed in between them. For instance, following code is illegal:
try{
}
System.out.print(“just testing”); // illegal
catch(Exception exp) {}
If both catch and finally clauses are present, the catch clauses must precede the finally clause.
The catch clause contains the exception handling code. Therefore, it is also called as an exception handler. It takes an object of java.lang.Throwable type as an argument.
The statements within a catch block are executed only when the exception of a same type as the one it is catching, is actually thrown within the try block.
The finally clause usually contains clean up code. It is executed even if the try block throws an exception or contains a return statement.
Order of execution of the exception handlers
When you define a catch block, it will catch all exception objects of the specified class including the exception objects of any of its subclasses. This way, you can handle a category of exception in a single catch block. Figure 5.2 shows a simple class hierarchy for java.io.IOException class.

Figure 5.2 Class hierarchy of IOException
If you have a file-handling code that is likely to throw either FileNotFoundException or EOFException and if you want to handle them, you may define two catch clauses. One that handles the FileNotFoundException and the other that handles the EOFException. If you want to handle both of them the same way, then these catch clauses will have same code in them. You can avoid such redundancy by defining a single catch clause for their superclass IOException. This clause will catch all exceptions of IOException type. Therefore, any exceptions of its subclass types are also handled. The following code has a single catch block for handling all IOException type of exceptions.
try {
// doing some file related stuff
} catch(IOException exp) {
// Common code for handling exception of IOException
// or any of its subtypes.
}
Suppose a FileNotFoundException occurs while executing the try block, then the matching catch for it is searched. Since we do not have a catch block for FileNotFoundException, the catch block for IOException is executed. Similarly, if EOFException occurs within try, it will be executed by the same catch block. Now what will you do if you want to handle only FileNotFoundException differently? You can specify the catch block for it. However, this catch block must precede the catch block of IOException. If not, then the FileNotFoundException’s catch block will be unreachable.
try {
// doing some file related stuff
} catch(FileNotFoundException fnfExp) { //Must come before IOException
// handling FileNotFoundException
} catch(IOException exp) {
// Common code for handling any
// generic I/O related exception
}
When FileNotFoundException actually occurs in try block, both the catch clauses are matching. However, the first catch block will be executed, since it is encountered first. What if the other subclasses of IOException, either EOFException or SocketException are thrown in try block? In that case, only the second catch clause will be matching and it is executed.
The Following rules come in handy when you face a code that has multiple catch clauses handling exceptions in a same class hierarchy.
A more specific exception handler must precede the more generalized one in the code. Otherwise a compiler error occurs. In other words, a catch clause handling an exception of a class must precede a catch clause handling exceptions of its superclass type (if any).
When an exception occurs, a matching catch clause is searched. Only the first matching catch block is executed.
|
|
In the exam, you may be tested on a code with multiple exception handlers. You may be asked how the control flows when a particular exception occurs. To answer this type of question, you need to know the class hierarchy of the exceptions involved. |