Chained Exceptions in Java with Example
Java 2, version 1.4 added a new feature chained exceptions. This feature relates one exception with another exception. The second exception explains the cause of the first exception.
Chained exception in Java is a technique to handle exceptions that occur one after another in a program. This technique helps us to know when one exception causes another in a program.
For example, let us assume that a, b, and c are objects of three different exception types A, B, and C, respectively. The object a of type A causes an exception of type B to occur and an object of B type also causes an exception of C type.
This process is called chaining of exceptions in Java, and the exceptions involved in this process are called chained exceptions. This feature helps the programmer to know when and where is the cause for the exception.
Constructors of Throwable Class to Support Chained Exceptions
To implement chained exceptions feature in JDK 1.4 version, Java added two constructors and two methods to Throwable class. The constructors that support chained exception in Java are as follows:
1. Throwable(Throwable causeExc):
This form of constructor creates a new Throwable object with the specified cause. It takes only one parameter: Throwable causeExc, which represents an exception that causes the current exception.
If the causeExc is null, it will return the null of message. Otherwise, it will return string representation of the message. The message contains the name of class and the detailed information of the cause.
2. Throwable(String msg, causeExc):
This form of constructor creates a new Throwable object with the specified detail message and cause. It takes two parameters: String msg and Throwable causeExc. Here, msg is an exception message and causeExc is an exception that causes the current exception.
Methods of Throwable Class to Support Chained Exceptions
There are the following methods added to the Throwable class that supports chained exceptions in Java.
1. toString(): This method returns an exception followed by a description of the exception. The general syntax is as follows:
public String toString()
2. getMessage(): It returns the description of exception. The general syntax is as:
public String getMessage()
3. printStackTrace(): This method displays stack trace. It returns nothing. The general syntax is given below.
public void printStackTrace()
4. getCause(): The getCause() method returns the exception that caused the occurrence of current exception. If there is no caused exception then null is returned. The syntax is as follows:
public Throwable getCause()
5. initCause(): The initCause() method joins “causeExc” with the invoking exception and returns a reference to the exception.
public Throwable initCause(Throwable causeExc)
Chained Exceptions Example Program
Let’s take an example program based on Java chained exceptions. In this example program, we are making ArithmeticException caused by StringIndexOutOfBoundsException, and StringIndexOutOfBoundsException caused by ArrayStoreException. Look at the program code below to understand better.
Example 1:
public class ChainedException {
static void chained()
{
// Create an instance of ArithmeticException class.
ArithmeticException a = new ArithmeticException();
// Create an instance of StringIndexOutBoundsException class.
StringIndexOutOfBoundsException b = new StringIndexOutOfBoundsException();
// Create an instance of ArrayStoreException class.
ArrayStoreException c = new ArrayStoreException();
Throwable t1 = b.initCause(a); // t1 is an object of type Throwable class.
Throwable t2 = c.initCause(b); // t2 is an object of type Throwable class.
System.out.println(b.getCause()+ " caused \n" +b);
System.out.println(c.getCause() + " caused \n" +c);
}
public static void main(String[] args)
{
// Calling static method.
chained();
}
}
Output: java.lang.ArithmeticException caused java.lang.StringIndexOutOfBoundsException java.lang.StringIndexOutOfBoundsException caused java.lang.ArrayStoreException
In this example, we have created a class named ChainedException, which contains a main method and a static method chained(). Inside the chained() method, we have created three different instances of ArithmeticException, StringIndexOutOfBoundsException, and ArrayStoreException, respectively.
Then, we have used initcause() method provided by java.lang.Throwable class. We use this method to associate one exception with another, creating a cause-and-effect relationship between them. The initCause() method allows us to specify one exception is the reason or cause for another exception to occur.
We generally call initCause() method on an instance of an exception class and set another exception as its cause. Look at the below example.
try {
// Some code that may throw an exception
} catch (Exception e) {
// Create an instance of exception and set 'e' as its cause
CustomException customException = new CustomException("An error occurred");
customException.initCause(e);
// Throw the new exception
throw customException;
}
The initcause() method takes a single argument, which should be another exception object (an instance of a class that extends Throwable). This argument represents the exception that caused the current exception to be thrown. This method returns a reference to the current exception object.
The statement Throwable t1 = b.initCause(a); means that exception b is set as the cause of exception a. Therefore, the reference variable t1 points to b as its cause. Similarly, exception c is set as the cause of exception b. Therefore, the reference variable t2 points to c as its cause.
The getCause() returns the exception that caused the occurrence of the current exception. The statement b.getCause() returns the cause of exception b, which is exception a, and prints it along with exception b itself.
As you can observe in the above program output, an ArithmeticException is raised by StringIndexOutOfBoundsException and StringIndexOutOfBoundsException is caused by ArrayStoreException. If the exception is not caused by another exception, the intiCause() method returns null.
Example 2:
public class OwnException extends Exception {
OwnException(String str)
{
super(str);
}
}
public class ChainedExcep {
public static void main(String[] args) throws OwnException
{
try {
int x = 10/0;
System.out.println("Result: " +x);
}
catch(ArithmeticException e)
{
System.out.println(e.getMessage());
System.out.println(e.getCause());
throw new OwnException("Chained Exception");
}
}
}
Output: / by zero null Exception in thread "main" chainedExceptions.OwnException: Chained Exception at chainedExceptions.ChainedExcep.main(ChainedExcep.java:15)
In this example, the user-defined exception throws an exception named ArithmeticException under the catch block. After throwing an exception, JVM will execute statements of catch block, and then call the user-defined constructor. Since the exception is not caused by another exception, the getCause() method returns null.
Example 3:
public class ChainedExceptionExample {
public static void main(String[] args)
{
try {
// Attempt some operation that might trigger an ArithmeticException
int result = divide(10, 0);
} catch (CustomException customException) {
System.out.println("CustomException caught: " + customException.getMessage());
Throwable cause = customException.getCause();
if (cause != null) {
System.out.println("Original Exception: " + cause.getMessage());
}
}
}
public static int divide(int dividend, int divisor)
{
try {
return dividend / divisor;
} catch (ArithmeticException e) {
// Throw a new exception with additional context
throw new CustomException("Division by zero is not allowed.", e);
}
}
}
// CustomException class extending RuntimeException to allow unchecked exceptions
class CustomException extends RuntimeException {
public CustomException(String message) {
super(message);
}
public CustomException(String message, Throwable cause) {
super(message, cause);
}
}
Output: CustomException caught: Division by zero is not allowed. Original Exception: / by zero
In this example, we have created a class named ChainedExceptionExample. Inside the main method, we have performed a division operation by calling the divide() method.
The divide() method performs division operation, but an ArithmeticException occurs. Instead of directly rethrowing the caught exception, it throws a new CustomException, passing the original exception (e) as its cause using the constructor with two parameters.
The CustomException class is a custom exception that extends RuntimeException. It provides constructors to set a custom error message and to specify a cause (another exception) using the Throwable parameter.
In the main method, if an exception occurs during division (in this case, division by zero), it is caught, and a new CustomException is thrown with additional context. The original exception is chained as the cause of the new exception.
By chaining exceptions in this manner, we have preserved the original exception’s information while adding context to make debugging and error diagnosis more informative and structured.
In this tutorial, we have explained almost all important points related to chained exceptions in Java with the help of some examples. Hope that you will have understood the chaining of exceptions in Java and practiced all example programs. In the next, we will understand Throwable class in Java with examples.
Thanks for reading!!!