Chaining Exceptions
It is common that the handling of an exception leads to the throwing of another exception. In fact, the first exception is the cause of the second exception being thrown. Knowing the cause of an exception can be useful, for example, when debugging the application. The Java API provides a mechanism for chaining exceptions for this purpose.
The class Throwable provides the following constructors and methods to handle chained exceptions:
Throwable(Throwable cause)
Throwable(String msg, Throwable cause)
Sets the throwable to have the specified cause, and also specifies a detail message if the second constructor is used. Most exception types provide analogous constructors.
Throwable initCause(Throwable cause)
Sets the cause of this throwable. Typically called on exception types that do not provide a constructor to set the cause.
Throwable getCause()
Returns the cause of this throwable, if any; otherwise, it returns null.
Example 7.14 illustrates how a chain of cause-and-effect exceptions, referred to as the backtrace, associated with an exception can be created and manipulated. In the method chainIt(), declared at (2), an exception is successively caught and associated as a cause with a new exception before the new exception is thrown, resulting in a chain of exceptions. This association is made at (3) and (4). The catch clause at (1) catches the exception thrown by the method checkIt(). The causes in the chain are successively retrieved by calling the getCause() method. Program output shows the resulting backtrace: which exception was the cause of which exception, and the order shown being reverse to the order in which they were thrown, the first one in the chain being thrown last.
Example 7.14 Chaining Exceptions
import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
public class ExceptionsInChain {
public static void main(String[] args) {
try {
chainIt();
} catch (Exception e) { // (1)
System.out.println(“Exception chain: ” + e);
Throwable t = e.getCause();
while (t != null) {
System.out.println(“Cause: ” + t);
t = t.getCause();
}
}
}
public static void chainIt() throws Exception { // (2)
try {
throw new FileNotFoundException(“File not found”);
} catch (FileNotFoundException e) {
try {
IOException ioe = new IOException(“File error”);
ioe.initCause(e); // (3)
throw ioe;
} catch (IOException ioe) {
Exception ee = new Exception(“I/O error”, ioe); // (4)
throw ee;
}
}
}
}
Output from the program:
Exception chain: java.lang.Exception: I/O error
Cause: java.io.IOException: File error
Cause: java.io.FileNotFoundException: File not found
A convenient way to print the backtrace associated with an exception is to invoke the printStackTrace() method on the exception. The catch clause at (1) in Example 7.14 can be replaced with the catch clause at (1′) below that calls the print-StackTrace() method on the exception.
…
try {
chainIt();
} catch (Exception e) { // (1′)
e.printStackTrace(); // Print backtrace.
}
…
The refactoring of Example 7.14 will result in the following analogous printout of the backtrace, showing as before the exceptions and their causes in the reverse order to the order in which they were thrown:
java.lang.Exception: I/O error
at ExceptionsInChain.chainIt(ExceptionsInChain.java:23)
at ExceptionsInChain.main(ExceptionsInChain.java:8)
Caused by: java.io.IOException: File error
at ExceptionsInChain.chainIt(ExceptionsInChain.java:19)
… 1 more
Caused by: java.io.FileNotFoundException: File not found
at ExceptionsInChain.chainIt(ExceptionsInChain.java:16)
… 1 more
Leave a Reply