Exception Chaining and Propagation

Exception chaining is an important feature of Java which allows one exception in a program to be associated with another exception. The purpose of using a chained exception is to identify the first exception that caused the second exception. Determining the underlying cause of an exception helps to identify and resolve the source of errors in a program, and ensure successful program completion.

Exception Chaining

In Java, multiple layers of exceptions can be associated with one another in the form of a chained exception and propagated to a higher-level exception handler. The Throwable class defines two constructors and two methods that enable you to work with the chained exceptions.

1. Chained Exception Constructors

The constructors in the Throwable class that support chained exceptions are:

Throwable (Throwable causeEx): Creates a Throwable instance and sets causeEx as the cause of the new exception. The “causeEx” parameter is the underlying exception that caused the current exception.

Throwable (String desc, Throwable causeEx): Creates a Throwable instance, adds a description, and sets “causeEx” as the cause of the new exception.

The two Throwable constructors for the chained exceptions are also available in the Error, Exception, and RuntimeException classes.

1.1 Chained Exception Methods

The methods in the Throwable class that support chained exceptions are:

Throwable getCause(): Returns the exception that caused the current exception. This method returns null if it does not find any underlying exception that resulted in the current exception.

Throwable initCause(Throwable causeEx): Sets the causeEx exception as the cause of the current exception and returns a reference to the current exception. This method can be used to associate the underlying cause with an exception that has already been created.

Note: For each exception object, you can set the cause exception only once.

Therefore, the initCause() method can be called only once for an exception object. However, if the cause of an exception object is already set by the constructor, then the initCause() method cannot be used to at all.

1.2 Example for Exception Chaining

The following program illustrates the use of chained exceptions:

ChainedExceptions.java
package com.onlinetutorialspoint.exceptions;
public class ChainedExceptions {
    static void exdemo() {
        NullPointerException e = new NullPointerException("Top Layer");
        e.initCause(new ArithmeticException("Underlying Cause"));
        throw e;
    }
    public static void main(String args[]) {
        try {
            exdemo();
        } catch (NullPointerException n) {
            System.out.println("Exception caught:" + n);
            System.out.println("Original cause of exception:" + n.getCause());
        }
    }
}

 In the try block of the main program, the exdemo() method is called. In this method, an ArithmeticException is set as the underlying cause of a NullPointerException. The initCause() method is used to make this association. The catch block in the main program catches the NullPointerException thrown by the exdemo() method. In the catch block, the getCause() method is used to obtain the cause associated with the NullPointerException.

Output:

Exception caught: java.lang.NullPointerException: Top Layer
Original cause of exception: java.lang.ArithmeticException: Underlying Cause

2. Debugging Chained Exceptions

When a high-level exception handler dumps the stack trace, you can use the information in the stack trace to debug chained exceptions. The stack trace displays the execution history and method invocations at the point in which an exception occurs. You can obtain the stack trace by invoking the getStackTrace() method on the exception object. The getStackTrace() method returns an array of stack trace elements that you can store in the Java StackTraceElement array.

The following code shows how to obtain information from the stack trace and store it into a file using Java’s logging feature available in the java.util.logging package.

ChainedExceptions.java
package com.onlinetutorialspoint.exceptions;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ChainedExceptions {
    public static void main(String args[]) {
        try {
            Handler hd = new FileHandler("OutputFile.log");
            Logger.getLogger("").addHandler(hd);
            throw new IOException();
        } catch (IOException e) {
            Logger lg = Logger.getLogger("com.onlinetutorialspoint.exceptions");
            StackTraceElement elmts[] = e.getStackTrace();
            for (int i = 0, n = elmts.length; i < n; i++) {
                lg.log(Level.WARNING, elmts[i].getMethodName());
            }
        }
    }
}

In this code, the contents of the stack trace are copied into the StrackTraceElement elmts[] array. The call of the method that occurred at the exception point is obtained from this stack trace array and stored into the log file OutputFile.log.

Happy Learning 🙂