February 26, 2021
Hot Topics:

The Essence of OOP using Java, Exception Handling

  • By Richard G. Baldwin
  • Send Email »
  • More Articles »

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,

"This ... includes any exception that can be thrown while the flow of control remains within the method. Thus, this ... includes both exceptions that are thrown directly by the method with Java's throw statement, and exceptions that are thrown indirectly by the method through calls to other methods."

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.

/*File Excep11.java 
Copyright 2002, R.G.Baldwin
Tested using JDK 1.4.0 under Win2000
import java.lang.Thread;

class Excep11{
  public static void main(
                        String[] args){
    Excep11 obj = new Excep11();
  }//end main
  void myMethod(){
  }//end myMethod
}//end class Excep11

Listing 1

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.

unreported exception 
must be caught or declared to be thrown

Figure 3

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.

/*File Excep12.java 
Copyright 2002, R.G.Baldwin
Tested using JDK 1.4.0 under Win2000
import java.lang.Thread;

class Excep12{
  public static void main(
                        String[] args){
    Excep12 obj = new Excep12();
  }//end main
  void myMethod() 
           throws InterruptedException{
  }//end myMethod
}//end class Excep12

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.

unreported exception 
must be caught or declared to be thrown

Figure 4

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.

(Note, however, that it is possible to declare that the main method throws a checked exception, which will cause the compiler to ignore it and allow your program to compile.)

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.

/*File Excep13.java 
Copyright 2002, R.G.Baldwin

Tested using JDK 1.4.0 under Win2000
import java.lang.Thread;

class Excep13{
  public static void main(
                        String[] args){
    Excep13 obj = new Excep13();
    try{//begin try block
    }catch(InterruptedException e){
              "Handle exception here");
    }//end catch block
  }//end main
  void myMethod() 
           throws InterruptedException{
  }//end myMethod
}//end class Excep13

Listing 3

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.

(Note, however, that the superclass cannot be higher than the Throwable class in the inheritance hierarchy.)

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:

  • Try to execute the code within the try block.
  • If an exception occurs, search for a catch block that matches the type of object thrown by the exception.
  • If such a catch block can be found, immediately transfer control to the catch block without executing any of the remaining code in the try block.  (For simplicity, this program didn't have any remaining code. Some later sample programs will illustrate code being skipped due to the occurrence of an exception.)

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.

/*File Excep14.java
Copyright 2002, R. G. Baldwin

Tested with JDK 1.4.0 under Win2000

class Excep14{
  public static void main(
                        String[] args){
      for(int cnt = 2; cnt >-1; cnt--){
               "Running. Quotient is: "
                              + 6/cnt);
      }//end for-loop
    }//end try block
    catch(ArithmeticException e){
              "Exception message is:  "
              + e.getMessage() 
              + "\nStacktrace shows:");
        "String representation is\n " +
         "Put corrective action here");
    }//end catch block
                 "Out of catch block");
  }//end main

}//end class Excep14

Listing 4

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.

(It would also be appropriate if the declared type of the parameter were a superclass of ArithmeticException, up to and including the class named ThrowableThrowable is a direct subclass of Object.  If you were to declare the parameter type for the catch block as Object, the compiler would produce an incompatible type error.)

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.

Running. Quotient is: 3
Running. Quotient is: 6
Exception message is:  / by zero
Stacktrace shows:
  / by zero
  at Excep14.main(Excep14.java:35)
String representation is
 / by zero
Put corrective action here
Out of catch block

Figure 5

Key things to note

The key things to note about the program in Listing 5 are:

  • The code to be protected is contained in a try block.
  • The try block is followed immediately by an appropriate catch block.
  • When an exception is thrown within the try block, control is transferred immediately to the catch block with the matching or appropriate parameter type.
  • Although the code in the catch block simply displays the current state of the program, it could contain code that attempts to rectify the problem.
  • Once the code in the catch block finishes executing, control is passed to the next executable statement following the catch block, which in this program is a print statement.

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,

"The first step in writing any exception handler is putting the Java statements within which an exception can occur into a try block. The try block is said to govern the statements enclosed within it and defines the scope of any exception handlers (established by subsequent catch blocks) associated with it."

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.

  //java statements 
}//end try block

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.

(Note that some statements, particularly those that invoke other methods, could potentially throw many different types of exceptions.)

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:

"Next, you associate exception handlers with a try block by providing one or more catch blocks directly after the try block."

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.

catch(ThrowableObjectType paramName){
  //Java statements to handle the
  // exception
}//end catch block

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:

"The catch block contains a series of legal Java statements. These statements are executed if and when the exception handler is invoked. The runtime system invokes the exception handler when the handler is the first one in the call stack whose type matches that of the exception thrown."

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:

"Your exception handler can be written to handle any class that inherits from Throwable. If you write a handler for a "leaf" class (a class with no subclasses), you've written a specialized handler: it will only handle exceptions of that specific type. If you write a handler for a "node" class (a class with subclasses), you've written a general handler: it will handle any exception whose type is the node class or any of its subclasses."

Page 2 of 3

This article was originally published on September 3, 2002

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date