Getty Images
An example of how suppressed exceptions in Java work
Don't ignore suppressed exceptions. In this quick tutorial we show you how to anticipate when code will throw suppressed exceptions, along with the best practices to handle them.
Java 7's try with resources statement created an unusual predicament for the creators of the language.
Prior to Java 7 a decade ago, a program could only generate one exception at a time. If a program threw an exception, it was either handled or the program would crash.
However, the try with resources statement created a situation where multiple exceptions could be thrown during an error handling routine. The first exception thrown gets handled normally. Subsequent exceptions get attached to the first as suppressed exceptions.
How suppressed exceptions occur
The sequence of events that triggers a suppressed exception is as follows:
- An AutoCloseable object is initialized in a try with resources statement.
- An exception occurs in the try block. This becomes the primary exception.
- The close() method of the AutoCloseable resource is invoked.
- The close() method throws its own exception.
- The exception thrown in the close() method is captured as a suppressed exception.
A developer can inspect any suppressed exceptions that occur by calling the primary exception's getSuppressedExceptions() method. This method enables the developer to perform additional logging or alerting based on errors that occurred in the AutoCloseable object's resource management routines.
Java's Automatic Resource Management
Here's a simple scenario that would generate a suppressed exception.
Imagine a class named Door that throws two exceptions:
- The SwingException is thrown when the door's swing() method is invoked.
- The CloseException is thrown when the door's close() method is invoked.
Here is the code for the Door class, and the two Java exceptions it throws:
class SwingException extends Exception {} class CloseException extends Exception {}
class Door implements AutoCloseable {
public void swing() throws Exception { System.out.println("The door is becoming unhinged!"); throw new SwingException(); /* Primary exception */ }
public void close() throws Exception { System.out.println("The door is now closed."); throw new CloseException(); /* Suppressed exception */ } }
If the Door class is used in a try with resources block that invokes its swing() method, this throws two exceptions. First is the SwingException, and second is the CloseException when the JVM performs automatic resource management.
Suppressed exception in Java example
In the following code example, the primary exception is the SwingException, while the CloseException is suppressed.
public class SuppressedExceptionExample {
public static void main(String[] args) throws Exception {
try ( Door door = new Door() ) { door.swing(); /* Throws the SwingException */ } catch (Exception e) { System.out.println("Primary Exception: " + e.getClass()); if (e.getSuppressed().length>0) { System.out.print("Suppressed Exception: " + e.getSuppressed()[0]); } } } }
In the suppressed exceptions example, the try with resources block creates an instance of the Door class, the swing() method is invoked, the primary exception is thrown, and then the suppressed exception is generated when the JVM invokes the AutoCloseable object's close() method.
The output generated when you run the main method is:
The door is becoming unhinged!
The door is now closed.
Primary Exception: SwingException
Suppressed Exception: CloseException
When the exception is handled, we can see that the SwingException is the primary, while the CloseException is listed as a suppressed exception.
Suppressed exception handling in Java
When developers use Java's automatic resource management features, suppressed exceptions will occur. Always inspect the primary exception to see if any suppressed exceptions are attached.
If suppressed exceptions do exist, apply standard exception handling strategies. Log the error, add code that will facilitate recovery from the exception, inform the user of why their request may have been interrupted, and optionally re-throw the exception to terminate the application.
If your program has the capacity to generate suppressed exceptions, handle them appropriately. Doing so will make your programs more effective, and easier for your fellow developers to troubleshoot.