This Java tutorial helps you understand the concept of exception chaining (or exception wrapping, exception propagation) and apply it to your Java daily coding.

 

1. What is Exception Chaining?

Basically, exception chaining is the process of re-throwing multiple exceptions across different abstraction layers of a program. The key principle here is that, these exceptions are chained together to maintain the stack trace from the exception at the lowest layer to the one at the highest layer. The following picture illustrates this concept visually:

exception chaining

As you can see, each abstraction layer defines its own exception classes. When code in a layer throws an exception, the higher layer re-throws it under a new type of exception which corresponds to the abstraction level of that layer. In turn, the next higher layer re-throws the exception under its own type of exception, and so on. This process continues until a layer handles the exception instead of re-throwing. During this chaining process, the higher exception always wraps the lower exception as its cause. Therefore, when an exception occurs, the programmer has a complete stack trace of the exceptions, which is very helpful for debugging.

 

2. Why is Exception Chaining?

The main purpose of exception chaining is to preserve the original exception when it propagates across multiple logical layers in a program. This is very helpful for the debugging process when an exception is thrown, as the programmer can analyze the full stack trace of the exceptions.

In addition, exception chaining also helps promoting abstraction among logical layers in a program, as each layer defines its own exceptions which are specific for that layer. For example, the StudentBusinessclass throws StudentException would be more meaningful than SQLException, right?

You know, exception chaining is sometimes referred as exception propagation, as when a layer throws an exception, the exception propagates through higher layers until a layer handles it such as displaying a message/warning to the user.

 

3. How to Chain Exceptions Together?

Let’s consider the following code example:

public void setBirthday(String birthDate) throws InvalidBirthdayException {
	DateFormat formatter = new SimpleDateFormat();
	try {
		Date birthday = formatter.parse(birthDate);
	} catch (ParseException ex) {
		throw new InvalidBirthdayException("Date of birth is invalid", ex);
	}
}

As you can see in the setBirthday() method, the ParseException is re-thrown under a new exception called InvalidBirthdayException. The ParseException is chained via the constructor of InvalidBirthdayException class:

throw new InvalidBirthdayException("Date of birth is invalid", ex);

This custom exception is implemented as following:

public class InvalidBirthdayException extends Exception {

	public InvalidBirthdayException(String message, Throwable cause) {
		super(message, cause);
	}
}

You can notice that, this constructor invokes its super’s constructor:

super(message, cause);

The supertypes of all exceptions Throwable and Exception implement this constructor, so any custom exceptions can call it. The origin exception (the cause) is passed to the being-created exception via its constructor.

Remember that the Exception class provides the following constructors that help chaining an exception:

  • Exception(Throwable cause)
  • Exception(String message, Throwable cause)

 

Besides chaining an exception via constructor, you can also chain an exception through the following Throwable’s method:

public Throwable initCause(Throwable cause)

That’s how exceptions are chained together.

 

Let’s see another example which is illustrated by the following picture:

exception chaining example

And following is source code of each class.

DAOException.java:

public class DAOException extends Exception {

	public DAOException(String message, Throwable cause) {
		super(message, cause);
	}
}

 

StudentException.java:

public class StudentException extends Exception {

	public StudentException(String message) {
		super(message);
	}

	public StudentException(String message, Throwable cause) {
		super(message, cause);
	}

}

 

DatabaseUtils.java:

import java.sql.*;

public class DatabaseUtils {
	public static void executeQuery(String sql) throws SQLException {
		throw new SQLException("Syntax Error");
	}
}

 

StudentDAO.java:

import java.sql.*;

public class StudentDAO {

	public void list() throws DAOException {
		try {

			DatabaseUtils.executeQuery("SELECT");

		} catch (SQLException ex) {
			throw new DAOException("Error querying students from database", ex);
		}
	}
}

 

StudentManager.java:

public class StudentManager {

	private StudentDAO dao;

	public StudentManager(StudentDAO dao) {
		this.dao = dao;
	}

	public void findStudents(String keyword) throws StudentException {
		try {
			dao.list();
		} catch (DAOException ex) {
			throw new StudentException("Error finding students", ex);
		}
	}
}

 

StudentProgram.java:

public class StudentProgram {

	public static void main(String[] args) {
		StudentDAO dao = new StudentDAO();
		StudentManager manager = new StudentManager(dao);

		try {

			manager.findStudents("Tom");

		} catch (StudentException ex) {
ex.printStackTrace();
		}
	}
}

 

Run the StudentProgram and you should see the following output:

StudentException: Error finding students
        at StudentManager.findStudents(StudentManager.java:13)
        at StudentProgram.main(StudentProgram.java:9)
Caused by: DAOException: Error querying students from database
        at StudentDAO.list(StudentDAO.java:11)
        at StudentManager.findStudents(StudentManager.java:11)
        ... 1 more
Caused by: java.sql.SQLException: Syntax Error
        at DatabaseUtils.executeQuery(DatabaseUtils.java:5)
        at StudentDAO.list(StudentDAO.java:8)
        ... 2 more

You see? The printed exception stack trace reveals an exception propagates from the DatabaseUtils layer up to the StudentProgram layer in which the exception is handled by printing this trace.

Now, let rewrite, compile and run the example to experiment the exception chaining yourself.

 

References:

 

Other Java Exception Handling Tutorials:


About the Author:

is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.



Add comment

   


Comments 

#3Abdul Rehman Shaikh2024-05-02 06:11
Thanks for sharing, nice article.
Quote
#2Noura2021-03-16 13:43
I want to trac coding
Quote
#1Oz2020-04-15 05:24
Thanks nice article. In the last example of the Student problem, the findStudents method doesn't actually do anything, I will just assume you have done this to show the stack trace rather than show a full working program. It can sometimes help a newbie if these things are completed.
Quote