Understanding Java Exception Chaining with Code Examples
- Details
- Written by Nam Ha Minh
- Last Updated on 10 July 2019   |   Print Email
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:
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:
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:
- 5 Rules about Catching Exceptions in Java
- Getting Started with Exception Handling in Java
- How to create custom exceptions in Java
- How to throw exceptions in Java - the differences between throw and throws
- Java Checked and Unchecked Exceptions
- Java exception API hierarchy - Error, Exception and RuntimeException
- Understanding Exception Stack Trace in Java with Code Examples
- What you may not know about the try-catch-finally construct in Java
Comments