The Essence of OOP using Java, Exception Handling

Baldwin discusses and illustrates many of the details having to do with exception handling in Java.

Published:  September 3, 2002
By Richard G. Baldwin

Java Programming Notes # 1630


Preface

This series of lessons is designed to teach you about the essence of Object-Oriented Programming (OOP) using Java.

The first lesson in the series was entitled The Essence of OOP Using Java, Objects, and Encapsulation.  The previous lesson was entitled The Essence of OOP using Java, The this and super Keywords.

You may find it useful to open another copy of this lesson in a separate browser window.  That will make it easier for you to scroll back and forth among the different listings while you are reading about them.

For further reading, see my extensive collection of online Java tutorials at Gamelan.com. A consolidated index is available at www.DickBaldwin.com.

Preview

This lesson explains Exception Handling in Java.  The discussion includes the following topics:

This lesson will cover many of the details having to do with exception handling in Java.  By the end of the lesson, you should know that the use of exception handling is not optional in Java, and you should have a pretty good idea how to use exception handling in a beneficial way.

Discussion and Sample Code

Introduction

Stated simply, the exception-handling capability of Java makes it possible for you to:

The basic concept

This is accomplished using the keywords: try, catch, throw, throws, and finally.  The basic concept is as follows:

Exceptions in code written by others

There are also situations where you don't write the code to throw the exception object, but an exceptional condition that occurs in code written by someone else transfers control to exception-handling code that you write.

For example, the read method of the InputStream class throws an exception of type IOException if an exception occurs while the read method is executing.  In this case, you are responsible only for the code in the catch block and optionally for the code in the finally block.

(This is the reason that you must surround the invocation of System.in.read() with a try block followed by a catch block, or optionally declare that your method throws an exception of type IOException.)

Exception hierarchy, an overview

When an exceptional condition causes an exception to be thrown, that exception is represented by an object instantiated from the class named Throwable or one of its subclasses.

Here is part of what Sun has to say about the Throwable class:

"The Throwable class is the superclass of all errors and exceptions in the Java language. Only objects that are instances of this class (or one of its subclasses) are thrown by the Java Virtual Machine or can be thrown by the Java throw statement.  Similarly, only this class or one of its subclasses can be the argument type in a catch clause."

Sun goes on to say:

"Instances of two subclasses, Error and Exception, are conventionally used to indicate that exceptional situations have occurred. Typically, these instances are freshly created in the context of the exceptional situation so as to include relevant information (such as stack trace data)."

The Error and Exception classes

The virtual machine and many different methods in many different classes throw exceptions and errors.  I will have quite a lot more to say about the classes named Error and Exception later in this lesson.

Defining your own exception types

You may have concluded from the Sun quotation given above that you can define and throw exception objects of your own design, and if you did, that is a correct conclusion. (Your new class must extend Throwable or one of its subclasses.)

The difference between Error and Exception

As mentioned above, the Throwable class has two subclasses:

What is an error?

What is the difference between an Error and an Exception?  Paraphrasing David Flanagan and his excellent series of books entitled Java in a Nutshell, an Error indicates that a non-recoverable error has occurred that should not be caught. Errors usually cause the Java virtual machine to display a message and exit.

Sun says the same thing in a slightly different way:

"An Error is a subclass of Throwable that indicates serious problems that a reasonable application should not try to catch.  Most such errors are abnormal conditions."

For example, one of the subclasses of Error is named VirtualMachineError.  This error is "Thrown to indicate that the Java Virtual Machine is broken or has run out of resources necessary for it to continue operating. "

What is an exception?

Paraphrasing Flanagan again, an Exception indicates an abnormal condition that must be properly handled to prevent program termination.

Sun explains it this way:

"The class Exception and its subclasses are a form of Throwable that indicates conditions that a reasonable application might want to catch."

As of JDK 1.4.0, there are more than fifty known subclasses of the Exception class.  Many of these subclasses themselves have numerous subclasses, so there is quite a lot of material that you need to become familiar with.

The RuntimeException class

One subclass of Exception is the class named RuntimeException As of JDK 1.4.0, this class has about 30 subclasses, many which are further subclassed.  The class named RuntimeException is a very important class.

Unchecked exceptions

The RuntimeException class, and its subclasses, are important not so much for what they do, but for what they don't do.  I will refer to exceptions instantiated from RuntimeException and its subclasses as unchecked exceptions.

Basically, an unchecked exception is a type of exception that you can optionally handle, or ignore.  If you elect to ignore the possibility of an unchecked exception, and one occurs, your program will terminate as a result.  If you elect to handle an unchecked exception and one occurs, the result will depend on the code that you have written to handle the exception.

Checked exceptions

All exceptions instantiated from the Exception class, or from subclasses of Exception other than RuntimeException and its subclasses must either be:

In other words, checked exceptions cannot be ignored when you write the code in your methods.  According to Flanagan, the exception classes in this category represent routine abnormal conditions that should be anticipated and caught to prevent program termination.

Checked by the compiler

Your code must anticipate and either handle or declare checked exceptions.  Otherwise, your program won't compile.  (These are exception types that are checked by the compiler.)

Throwable constructors and methods

As mentioned above, all errors and exceptions are subclasses of the Throwable class.  As of JDK 1.4.0, the Throwable class provides four constructors and about a dozen methods.  The four constructors are shown in Figure 1.
 

Throwable()
Throwable(String message) 
Throwable(String message, 
          Throwable cause) 
Throwable(Throwable cause)

Figure 1

The first two constructors have been in Java for a very long time.  Basically, these two constructors allow you to construct an exception object with, or without a String message encapsulated in the object.

New to JDK 1.4

The last two constructors are new in JDK 1.4.0.  These two constructors are provided to support the cause facility. The cause facility is new in release 1.4. It is also known as the chained exception facility.  (I won't cover this facility in this lesson.  Rather, I plan to cover it in a series of lessons that I am developing having to do with the myriad of new features in JDK 1.4.)

Methods of the Throwable class

Figure 2 shows some of the methods of the Throwable class. (I omitted some of the methods introduced in JDK 1.4 for the reasons given above.)
 

fillInStackTrace()
getStackTrace() 
printStackTrace().
setStackTrace(StackTraceElement[] 
                           stackTrace)
getLocalizedMessage() 
getMessage()
toString()
Figure 2

The StackTrace

The first four methods in Figure 2 deal with the StackTrace.  In case you are unfamiliar with the term StackTrace, this is a list of the methods executed in sequence that led to the exception.  (This is what you typically see on the screen when your program aborts with a runtime error that hasn't been handled.)

Messages

The two methods dealing with messages provide access to a String message that may be encapsulated in the exception object.  The getMessage class simply returns the message that was encapsulated when the object was instantiated.  (If no message was encapsulated, this method returns null.)

The getLocalizedMessage method is a little more complicated to use.  According to Sun, "Subclasses may override this method in order to produce a locale-specific message."

The toString method

The toString method is inherited from the Object class and overridden in the exception subclass to "return a short description of the Throwable".

Inherited methods

All exception objects inherit the methods of the Throwable class, which are listed in Figure 2.  Thus, any of these methods may be invoked by the code in the catch block in its attempt to successfully handle the exception.

For example, exceptions may have a message encapsulated in the exception object, which can be accessed using the getMessage method. You can use this to display a message describing the error or exception.

You can also use other methods of the Throwable class to:

So, what is an exception?

According to the online book entitled The Java Tutorial by Campione and Walrath:

"The term exception is shorthand for the phrase "exceptional event". It can be defined as follows: Definition: An exception is an event that occurs during the execution of a program that disrupts the normal flow of instructions."

When an exceptional condition occurs within a method, the method may instantiate an exception object and hand it off to the runtime system to deal with it.  This is accomplished using the throw keyword.  (This is called throwing an exception.)

To be useful, the exception object should probably contain information about the exception, including its type and the state of the program when the exception occurred.

Handling the exception

At that point, the runtime system becomes responsible for finding a block of code designed to handle the exception.

The runtime system begins its search with the method in which the exception occurred and searches backwards through the call stack until it finds a method that contains an appropriate exception handler (catch block).

An exception handler is appropriate if the type of the exception thrown is the same as the type of exception handled by the handler, or is a subclass of the type of exception handled by the handler.

Thus, the requirement to handle an exception that has been thrown progresses up through the call stack until an appropriate handler is found to handle the exception. If no appropriate handler is found, the runtime system and the program terminate.

(If you have ever had a program terminate with a NullPointerException, then you know how program termination works).

According to the jargon, the exception handler that is chosen is said to catch the exception.

Advantages of using exception handling

According to Campione and Walrath, exception handling provides the following advantages over "traditional" error management techniques:

Separating error handling code from regular code

I don't plan to discuss these advantages in detail. Rather, I will simply refer you to The Java Tutorial and other good books where you can read their discussions. However, I will comment briefly.

Campione and Walrath provide a good illustration where they show how a simple program having about six lines of code get "bloated" into about 29 lines of very confusing code through the use of traditional error management techniques. Not only does the program suffer bloat, the logical flow of the original program gets lost in the clutter of the modified program.

They then show how to accomplish the same error management using exception handling. Although the version with exception handling contains about seventeen lines of code, it is orderly and easy to understand. The additional lines of code do not cause the original logic of the program to get lost.

You must still do the hard work

However, the use of exception handling does not spare you from the hard work of detecting, reporting, and handling errors.  What it does is provide a means to separate the details of what to do when something out-of-the-ordinary happens from the normal logical flow of the program code.

Propagating exceptions up the call stack

Sometimes it is desirable to propagate exception handling up the call stack and let the corrective action be taken at a higher level.

For example, you might provide a class with methods that implement a stack. One of the methods of your class might be to pop an element off the stack.

What should your program do if a using program attempts to pop an element off an empty stack? That decision might best be left to the user of your stack class, and you might simply propagate the notification up to the calling method and let that method take the corrective action.

Grouping exception types

When an exception is thrown, an object of one of the exception classes is passed as a parameter.  Objects are instances of classes, and classes fall into an inheritance hierarchy in Java.  Therefore, a natural hierarchy can be created, which causes exceptions to be grouped in logical ways.

For example, going back to the stack example, you might create an exception class that applies to all exceptional conditions associated with an object of your stack class. Then you might extend that class into other classes that pertain to specific exceptional conditions, such as push exceptions, pop exceptions, and initialization exceptions.

When your code throws an exception object of a specific type, that object can be caught by an exception handler designed either to:

In other words, an exception handler can catch exceptions of the class specified by the type of its parameter, or can catch exceptions of any subclass of the class specified by the type of its parameter.

More detailed information on exception handling

As explained earlier, except for Throwable objects of type Error and for Throwable.Exception objects of type RuntimeException, Java programs must either handle or declare all Exception objects that are thrown.  Otherwise, the compiler will refuse to compile the program.

In other words, all exceptions other than those specified above are checked by the compiler, and the compiler will refuse to compile the program if the exceptions aren't handled or declared.  As a result, exceptions other than those specified above are often referred to as checked exceptions.

Catching an exception

Just to make certain that we are using the same terminology, a method catches an exception by providing an exception handler whose parameter type is appropriate for that type of exception object.  (I will more or less use the terms catch block and exception handler interchangeably.)

The type of the parameter in the catch block must be the class from which the exception was instantiated, or a superclass of that class that resides somewhere between that class and the Throwable class in the inheritance hierarchy.

Declaring an exception

If the code in a method can throw a checked exception, and the method does not provide an exception handler for the type of exception object thrown, the method must declare that it can throw that exception.  The throws keyword is used in the method declaration to declare that it throws an exception of a particular type.

Any checked exception that can be thrown by a method is part of the method's programming interface (see the read method of the InputStream class, which throws IOException, for example).  Users of a method must know about the exceptions that a method can throw in order to be able to handle them. Thus, you must declare the exceptions that the method can throw in the method signature.

Checked exceptions

Checked exceptions are all exception objects instantiated from subclasses of the Exception class other than those of the RuntimeException class.

Exceptions of all Exception subclasses other than RuntimeException are checked by the compiler and will result in compiler errors if they are neither caught nor declared.

You will learn how you can create your own exception classes later. Whether your exception objects become checked or not depends on the class that you extend when you define your exception class.

(If you extend a checked exception class, your new exception type will be a checked exception.  Otherwise, it will not be a checked exception.)

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();
    obj.myMethod();
  }//end main
  //---------------------------------//
  
  void myMethod(){
    Thread.currentThread().sleep(1000);
  }//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 
java.lang.InterruptedException; 
must be caught or declared to be thrown
    Thread.currentThread().sleep(1000);
                        ^

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();
    obj.myMethod();
  }//end main
  //---------------------------------//
  
  void myMethod() 
           throws InterruptedException{
    Thread.currentThread().sleep(1000);
  }//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 
java.lang.InterruptedException; 
must be caught or declared to be thrown
    obj.myMethod();
       ^

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
      obj.myMethod();
    }catch(InterruptedException e){
      System.out.println(
              "Handle exception here");
    }//end catch block
  }//end main
  //---------------------------------//
  
  void myMethod() 
           throws InterruptedException{
    Thread.currentThread().sleep(1000);
  }//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:

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){
    try{
      for(int cnt = 2; cnt >-1; cnt--){
        System.out.println(
               "Running. Quotient is: "
                              + 6/cnt);
      }//end for-loop
    }//end try block
    catch(ArithmeticException e){
      System.out.println(
              "Exception message is:  "
              + e.getMessage() 
              + "\nStacktrace shows:");
      e.printStackTrace();
      System.out.println(
        "String representation is\n " +
                         e.toString());
      System.out.println(
         "Put corrective action here");
    }//end catch block
    System.out.println(
                 "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:
java.lang.ArithmeticException: 
  / by zero
  at Excep14.main(Excep14.java:35)
String representation is
 java.lang.ArithmeticException: 
 / 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:

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.
 

try{ 
  //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."

You have a choice

Therefore, when writing exception handlers, you have a choice.  You can write a handler whose exception type corresponds to a node in the inheritance hierarchy, and it will be appropriate to catch exceptions of that type, or any subclass of that type.

Alternately, you can write a handler whose exception type corresponds to a leaf, in which case, it will be appropriate to catch exceptions of that type only.

And finally, you can mix and match, writing some exception handlers whose type corresponds to a node, and other exception handlers whose type corresponds to a leaf.  In all cases, however, be sure to position your exception handlers in reverse subclass order, with the furthermost subclass from the root appearing first, and the root class appearing last.

The finally block

And finally (no pun intended), Campione and Walrath tell us:

"Java's finally block provides a mechanism that allows your method to clean up after itself regardless of what happens within the try block. Use the finally block to close files or release other system resources."

To elaborate, the finally block can be used to provide a mechanism for cleaning up open files, etc., before allowing control to be passed to a different part of the program.  You accomplish this by writing the cleanup code within a finally block.

Code in finally block is always executed

It is important to remember that the runtime system always executes the code within the finally block regardless of what happens within the try block.

If no exceptions are thrown, none of the code in catch blocks is executed, but the code in the finally block is executed.

If an exception is thrown and the code in an exception handler is executed, once the execution of that code is complete, control is passed to the finally block and the code in the finally block is executed.

(There is one important exception to the above.  If the code in the catch block terminates the program by executing System.exit(0), the code in the finally block will not be executed.)

The power of the finally block

The sample program shown in Listing 5 illustrates the power of the finally block.
 

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

Tested with JDK 1.4.0 under Win2000
**************************************/

class Excep15{
  public static void main(
                        String[] args){
    new Excep15().aMethod();
  }//end main
  //---------------------------------//
                          
  void aMethod(){
    try{
      int x = 5/0;
    }//end try block
    catch(ArithmeticException e){
      System.out.println(
      "In catch, terminating aMethod");
      return;
    }//end catch block
    
    finally{
      System.out.println(
            "Executing finally block");
    }//end finally block

    System.out.println(
                "Out of catch block");
  }//end aMethod

}//end class Excep15 

Listing 5

Execute return statement in catch block

The code in Listing 5 forces an ArithmeticException by attempting to do an integer divide by zero.  Control is immediately transferred to the matching catch block, which prints a message and then executes a return statement.

Normally, execution of a return statement terminates the method immediately.  In this case, however, before the method terminates and returns control to the calling method, the code in the finally block is executed.  Then control is transferred to the main method, which called this method in the first place.

Figure 8 shows the output produced by this program.
 

In catch, terminating aMethod
Executing finally block

Figure 8

This program demonstrates that the finally block really does have the final word.

Declaring exceptions thrown by a method

Sometimes it is better to handle exceptions in the method in which they are detected, and sometimes it is better to pass them up the call stack and let another method handle them.

In order to pass exceptions up the call stack, you must declare them in your method signature.

To declare that a method throws one or more exceptions, you add a throws clause to the method signature for the method. The throws clause is composed of the throws keyword followed by a comma-separated list of all the exceptions thrown by that method.

The throws clause goes after the method name and argument list and before the curly bracket that defines the scope of the method.

Figure 9 shows the syntax for declaring that a method throws four different types of exceptions.
 

void myMethod() throws 
          InterruptedException, 
          MyException, 
          HerException, 
          UrException
{
  //method code
}//end myMethod()

Figure 9

Assuming that these are checked exceptions, any method calling this method would be required to either handle these exception types, or continue passing them up the call stack. Eventually, some method must handle them or the program won't compile.

(Note however that while it might not represent good programming practice, it is allowable to declare that the main method throws exceptions.  This is a way to avoid handling checked exceptions and still get your program to compile.)

The throw keyword

Before your code can catch an exception, some Java code must throw one. The exception can be thrown by code that you write, or by code that you are using that was written by someone else.

Regardless of who wrote the code that throws the exception, it's always thrown with the Java throw keyword.  At least that is true for exceptions that are thrown by code written in the Java language.

(Exceptions such as ArithmeticException are also thrown by the runtime system, which is probably not written using Java source code.)

A single argument is required

When formed into a statement, the throw keyword requires a single argument, which must be a reference to an object instantiated from the Throwable class, or any subclass of the Throwable class.  Figure 10 shows an example of such a statement.
 

throw new myThrowableClass("Message");

Figure 10

If you attempt to throw an object that is not instantiated from Throwable or one of its subclasses, the compiler will refuse to compile your program.

Defining your own exception classes

Now you know how to write exception handlers for those exception objects that are thrown by the runtime system, and thrown by methods in the standard class library.

It is also possible for you to define your own exception classes, and to cause objects of those classes to be thrown whenever an exception occurs.  In this case, you get to decide just what constitutes an exceptional condition.

For example, you could write a data-processing application that processes integer data obtained via a TCP/IP link from another computer.  If the specification for the program indicates that the integer value 10 should never be received, you could use an occurrence of the integer value 10 to cause an exception object of your own design to be thrown.

Choosing the exception type to throw

Before throwing an exception, you must decide on its type.  Basically, you have two choices in this regard:

An important question

So, an important question is, when should you define your own exception classes and when should you use classes that are already available.  Because this is only one of many design issues, I'm not going to try to give you a ready answer to the question.  However, I will refer you to The Java Tutorial by Campione and Walrath where you will find a checklist to help you make this decision.

Choosing a superclass to extend

If you decide to define your own exception class, it must be a subclass of Throwable. You must decide which class you will extend.

The two existing subclasses of Throwable are Exception and Error. Given the earlier description of Error and its subclasses, it is not likely that your exceptions would fit the Error category. (In concept, errors are reserved for serious hard errors that occur deep within the system.)

Checked or unchecked exception

Therefore, your new class should probably be a subclass of Exception.  If you make it a subclass of RuntimeException, it won't be a checked exception.  If you make it a subclass of Exception, but not a subclass of RuntimeException, it will be a checked exception.

Only you can decide how far down the Exception hierarchy you want to go before creating a new branch of exception classes that are unique to your application.

Naming conventions

Many Java programmers append the word Exception to the end of all class names that are subclasses of Exception, and append the word Error to the end of all class names that are subclasses of Error.

One more sample program

Let's wrap up this lesson with one more sample program named Excep16.  We will define our own exception class in this program. Then we will throw, catch and process an exception object instantiated from that class.

Discuss in fragments

This program is a little longer than the previous programs, so I will break it down and discuss it in fragments.  A complete listing of the program is shown in Listing 10.

The class definition shown in Listing 6 is used to construct a custom exception object that encapsulates a message.  Note that this class extends Exception(Therefore, it is a checked exception.)
 

class MyException extends Exception{
  MyException(String message){//constr
    super(message);
  }//end constructor
}//end MyException class

Listing 6

The constructor for this class receives an incoming String message parameter and passes it to the constructor for the superclass.  This makes the message available for access by the getMessage method invoked in the catch block.

The try block

Listing 7 shows the beginning of the main method, including the entire try block
 

class Excep16{//controlling class
  public static void main(
                        String[] args){
    try{
      for(int cnt = 0; cnt < 5; cnt++){
        //Throw a custom exception, and
        // pass  message when cnt == 3
        if(cnt == 3) throw 
                  new MyException("3");
        //Transfer control before 
        // processing for cnt == 3
        System.out.println(
           "Processing data for cnt = "
                                + cnt);
      }//end for-loop
    }//end try block

Listing 7

The main method executes a for loop (inside the try block) that guarantees that the variable named cnt will reach a value of 3 after a couple of iterations.

Once during each iteration, (until the value of cnt reaches 3) a print statement inside the for loop displays the value of cnt.  This results in the output shown in Figure 11.
 

Processing data for cnt = 0
Processing data for cnt = 1
Processing data for cnt = 2

Figure 11

What happens when cnt equals 3?

However, when the value of cnt equals 3, the throw statement highlighted in boldface in Listing 7 is executed.  This causes control to transfer immediately to the matching catch block following the try block (see Listing 8).  During this iteration, the print statement following the throw statement is not executed.  Therefore, the output never shows a value for cnt greater than 2, as shown in Figure 11.

The catch block

Listing 8 shows a catch block whose type matches the type of exception thrown in Listing 7.
 

    catch(MyException e){
      System.out.println(
               "In exception handler, "
                  + "get the message\n"
                     + e.getMessage());
    }//end catch block

Listing 8

When the throw statement is executed in Listing 7, control is transferred immediately to the catch block in Listing 8.  No further code is executed within the try block.

A reference to the object instantiated as the argument to the throw keyword in Listing 7 is passed as a parameter to the catch block.  That reference is known locally by the name e inside the catch block.

Using the incoming parameter

The code in the catch block invokes the method named getMessage (inherited from the Throwable class) on the incoming parameter and displays that message on the screen.  This produces the output shown in Figure 12.
 

In exception handler, get the message
3

Figure 12

When the catch block finishes execution ...

When the code in the catch block has completed execution, control is transferred to the first executable statement following the catch block as shown in Listing 9.
 

    System.out.println(
      "Out of catch block");
  }//end main
}//end class Excep16


Listing 9

That executable statement is a print statement that produces the output shown in Figure 13.
 

Out of catch block

Figure 13

A complete listing of the program is shown in Listing 10.
 

/*File Excep16.java  
Copyright 2002, R. G. Baldwin
Illustrates defining, throwing, 
catching, and processing a custom 
exception object that contains a 
message.

Tested using JDK 1.4.0 under Win 2000

The output is:

Processing data for cnt = 0

Processing data for cnt = 1
Processing data for cnt = 2
In exception handler, get the message
3
Out of catch block
**************************************/

//The following class is used to 
// construct a customized exception 
// object containing a message
class MyException extends Exception{
  MyException(String message){//constr
    super(message);
  }//end constructor
}//end MyException class
//===================================//

class Excep16{//controlling class
  public static void main(
                        String[] args){
    try{
      for(int cnt = 0; cnt < 5; cnt++){
        //Throw a custom exception, and
        // pass  message when cnt == 3
        if(cnt == 3) throw 
                  new MyException("3");
        //Transfer control before 
        // processing for cnt == 3
        System.out.println(
           "Processing data for cnt = "
                                + cnt);
      }//end for-loop
    }//end try block
    catch(MyException e){
      System.out.println(
               "In exception handler, "
                  + "get the message\n"
                     + e.getMessage());
    }//end catch block
    //-------------------------------//
    
    System.out.println(
      "Out of catch block");
  }//end main

Listing 10

Summary

This lesson has covered many of the details having to do with exception handling in Java.  By now, you should know that the use of exception handling is not optional in Java, and you should have a pretty good idea how to use exception handling in a beneficial way.

Along the way, the discussion has included the following topics:

What's Next?

For the time being, that completes the miniseries entitled "The Essence of OOP using Java."  I may decide to come back later and add some lessons on inner classes and other similar topics, but it will probably be a while before I get around to that.  In the meantime, I sincerely hope that you have enjoyed this miniseries, and have found the lessons useful in your continuing effort to learn and understand OOP as implemented using Java.


Copyright 2002, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, Texas) and private consultant whose primary focus is a combination of Java, C#, and XML. In addition to the many platform and/or language independent benefits of Java and C# applications, he believes that a combination of Java, C#, and XML will become the primary driving force in the delivery of structured information on the Web.

Richard has participated in numerous consulting projects, and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas.  He is the author of Baldwin's Programming Tutorials, which has gained a worldwide following among experienced and aspiring programmers. He has also published articles in JavaPro magazine.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

baldwin@DickBaldwin.com

-end-