Java Suppressed Exceptions

Today I learned something new about Java exceptions. The always surprising try-catch statement has a concept called suppressed exceptions. The main idea is that a the whole try structure can throw an exception from more than one place:

  • The catch block
  • The finally block
  • The try-with-resources implicit close


The problem is this: methods can only throw one exception in the end. So, what happens to the other thrown exceptions? The catch block can rethrow its exception, the finally can throw a new one and the close can cause an IOException all in the same call. We can read the Java Language Specification (JLS) to figure it out, but first an experiment.

import java.io.OutputStream;
import org.apache.commons.io.output.BrokenOutputStream;

public class Test {

    public static void main(String[] args) throws Exception {
        try {
            whichException();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    public static void whichException() {
        try (OutputStream out = new BrokenOutputStream()) {
            throw new IllegalArgumentException("In the try");
        } catch (Exception ex) {
            throw new IllegalArgumentException("In the catch");
        } finally {
            throw new IllegalArgumentException("In the finally");
        }
}

}

The experiment uses a stream from Apache’s CommonsIO library which throws exceptions on any operation to shorten the code.

Do you know without running the example what the console will print?




It prints “In the finally”. This will be the first surprise. If you print some tracing messages throughout the code you’ll see that all three exceptions are thrown. First the one inside the try, then the one in the implicit close of the stream (suppressed), then the one in the catch block, and at last the one in the finally block. But this is about suppressed exceptions, like the one in the catch block. So now let’s try this:

    public static void main(String[] args) throws Exception {
        try {
            whichException();
        } catch (Exception e) {
            System.out.println(e);
            for (Throwable suppressed : e.getSuppressed()) {
                System.out.println(suppressed);
            }
            System.out.println(e.getCause());
        }
    }

    public static void whichException() {
        try (OutputStream out = new BrokenOutputStream()) {
            throw new IllegalArgumentException("In the try");
        } catch (Exception ex) {
            throw new IllegalArgumentException("In the catch", ex);
        } finally {
            // throw new IllegalArgumentException("In the finally");
        }
    }

The change comments out the exception in the finally and links the one thrown in the catch clause with the original. Now we can retrieve those suppressed exceptions from the exception that results from the whichException() method. If the try-with-resources block has multiple resources, each implicit close can throw its own exception. That’s why getSuppressed() returns an array.

I take two lessons from this exploration. First, do not throw or return from a finally clause. Second, a catch clause in a try-with-resources should consider the suppressed exceptions when reacting or logging. :>

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.