Suppressed Exceptions

One additional detail to consider is that, if the code within the final {} block is throwing an exception itself (e.g. if the close() method is throwing an SQL exception), what happens with this exception (and does it have an impact on the original exception?). To further explore this, we use this sample code:

package net.littletux.java7;

public class ExceptionHandling {

    public static void main(String[] args) {
        ExceptionHandling eh = new ExceptionHandling();
        try {
            System.out.println("Old approach: ");
            eh.oldApproach();
        }catch(Exception e) {
            e.printStackTrace();
        }

       try {
          System.out.println("\nNew approach: ");
          eh.newApproach();
       }catch(Exception e) {
           e.printStackTrace();
       }
    }

    class CloseableClass implements AutoCloseable {
        public void someMethod() {
             System.err.println("Doing the work ...");
             throw new RuntimeException("CloseableClass.someMethod");
         }

        public void close() {
            System.err.println("Closing object...");
           throw new RuntimeException("CloseableClass.close");
        }
    }

    public void oldApproach() {
        CloseableClass obj = null;
        try {
            obj = new CloseableClass();
            obj.someMethod();
         } finally {
             if (obj != null) {
                 obj.close();
             }
         }
    }

    public void newApproach() {
        try (CloseableClass obj = new CloseableClass()) {
             obj.someMethod();
        }
    }
}

The code should be quite straightforward: the main class calls two methods, oldApproach() and newApproach(), which might throw some exception. The exception is catched and the stacktrace is printed out. Then we define our own class which implements the AutoCloseable interface, so that it can be used with the try-with-resources statement. The class contains a method which does some work, but throws an exception. The class also contains a close() method which also throws an exception. The class is then used in the two methods oldApproach() and newApproach() and we want to make sure that the close() method is called in any case, even if an exception is thrown. Now, when we have a look at the stack traces printed after calling the oldApproach() method, we observe that the stack trace only contains the exception which is thrown in the close() method, not the original one which has been thrown in someMethod() – this exception is not even mentioned in the stack trace! It has been silently suppressed.

Doing the work ...
Closing object...
java.lang.RuntimeException: CloseableClass.close
    at net.littletux.java7.ExceptionHandling$CloseableClass.close(ExceptionHandling.java:33)
    at net.littletux.java7.ExceptionHandling.oldApproach(ExceptionHandling.java:47)
    at net.littletux.java7.ExceptionHandling.main(ExceptionHandling.java:11)

On the other hand, when we examine  the stack trace which is printed after calling the newApproach() method, we see that the strack trace contains both exceptions:

Doing the work ...
Closing object...
java.lang.RuntimeException: CloseableClass.someMethod
    at net.littletux.java7.ExceptionHandling$CloseableClass.someMethod(ExceptionHandling.java:28)
    at net.littletux.java7.ExceptionHandling.newApproach(ExceptionHandling.java:54)
    at net.littletux.java7.ExceptionHandling.main(ExceptionHandling.java:18)
    Suppressed: java.lang.RuntimeException: CloseableClass.close
        at net.littletux.java7.ExceptionHandling$CloseableClass.close(ExceptionHandling.java:33)
        at net.littletux.java7.ExceptionHandling.newApproach(ExceptionHandling.java:55)
        ... 1 more

Usually the exception thrown within the try {} – block is more important than the exception thrown by close(), since the real work is done within the try {} – block. As we see, the stack trace now primarily contains the exception thrown within the try {} – block, and in addition still contains the exception thrown in the close() method as suppressed exception. Suppressed exceptions are printed in the stack trace, and the Exception class has methods to retrieve the suppressed exceptions manually and to add additional suppressed exceptions.