Chained Exceptions

The chained exception feature allows us to associate another exception with an exception. Here the second exception describes the cause of the first exception. For example, imagine a situation in which a method throws an NullPointerException because of a failed attempt to initialize an object reference. However, the actual cause of the problem was that an IOException (I/O exception) occurred, which caused the object reference to be initialized improperly and as a result it becomes null. Although the method must certainly throw an NullPointerException, since that is the error that occurred, we might also want to let the calling code know that the underlying cause was the IOException. Chained exceptions let us handle this and any other situation in which layers of exceptions exist.

To allow chained exceptions, Java added two constructors and two methods to Throwable. The constructors are shown here:

Throwable(Throwable causeException)
Throwable(String message, Throwable causeException)

 

In the first form, causeException is the exception that causes the current exception. That is, causeException is the underlying reason that an exception occurred. The second form allows us to specify a description at the same time that we specify a cause exception. These two constructors have also been added to the Error, Exception, and RuntimeException classes. The chained exception methods added to Throwable are getCause( ) and initCause( ).

Throwable getCause( )
Throwable initCause(Throwable causeException)  

 

The getCause( ) method returns the exception that underlies the current exception. If there is no underlying exception, null is returned. The initCause( ) method associates causeException with the invoking exception and returns a reference to the exception. Thus, we can associate a cause with an exception after the exception has been created. However, the cause exception can be set only once. Thus, we can call initCause( ) only once for each exception object. Furthermore, if the cause exception was set by a constructor, then we can’t set it again using initCause( ).

In general, initCause( ) is used to set a cause for legacy exception classes which don’t support the two additional constructors described earlier. At the time of this writing, most of Java’s built-in exceptions, such as NullPointerException, do not define the additional constructors. Thus, we will use initCause( ) if we need to add an exception chain to these exceptions. When creating our own exception classes we will want to add the two chained-exception constructors if we will be using our exceptions in situations in which layered exceptions are possible. Here is a program (Except11.java) that illustrates the mechanism of handling chained exceptions:

import java.io.IOException;

public class Except11 {

static void test() {
//creating an exception
NullPointerException e = new NullPointerException("top level");
//adding a cause
e.initCause(new IOException("cause"));
throw e;
}

public static void main(String args[]) {
try {
test();
}
catch (NullPointerException e) {
//displaying top level exception
System.out.println("Caught = " + e);
//displaying cause exception
System.out.println("Original cause = " + e.getCause());
}
}
}

 

The output of the program is given below:

Caught = java.lang.NullPointerException: top level
Original cause = java.io.IOException: cause

 

In this example, the top-level exception is NullPointerException. To it we have added a cause exception named IOException. When the exception is thrown out of test( ), it is caught by main( ). There, the top-level exception is displayed, followed by the underlying exception, which is obtained by calling getCause( ). Chained exceptions can be carried on to whatever depth is necessary. Thus, the cause exception can, itself, have a cause. Be aware that overly long chains of exceptions may indicate poor design. Chained exceptions are not something that every program will need. However, in cases in which knowledge of an underlying cause is useful, they offer an elegant solution.