At any point of time only one exception can be thrown by a method per execution. In cases when more than one exception would be thrown from the method, one of them will be suppressed and not thrown by the compiler. This exception is known as the suppressed exceptions in Java.
- Additional Reading : Java Exceptions Tutorial
In Java 7, the most common scenario for getting the suppressed exception is when using the try-with-resource statement. Try with resources statement is a special type of try block introduced in Java 7 of try that doesn’t require a catch or finally block.
Suppressed Exceptions Example
When using the try with resources statement, first exception will occur in the try block and then probably encounters another exception while closing the resource. The second exception will be implicitly thrown hence that will be suppressed. Since multiple exceptions are thrown while closing the resources, additional exceptions are attached to the primary exception as the suppressed exceptions.
Java 7 have added a new constructor and two new methods in the Throwable
class as below:
Throwable.getSupressed(); // Returns Throwable[] Throwable.addSupressed(aThrowable);
Let’s look at a simple example on how to use the suppressed exception methods in the Throwable
class to retrieve the suppressed exceptions.
Here is the implementation for the Resource class
public class Resource implements AutoCloseable { public void use() { throw new RuntimeException("This exception in the use method"); } @Override public void close() throws Exception { throw new NullPointerException("This exception in the close method"); } }
Now let’s look at the different scenarios to understand the suppressed exceptions prior to Java 7 and after Java 7 support.
1. Without Suppressed Exceptions Support
import static java.lang.System.err; public class ExceptionExample { public static void test() throws Exception { Resource resource = new Resource(); try { resource.use(); } finally { resource.close(); } } public static void main(String args[]) { try { test(); } catch (Exception ex) { err.println("Exception encountered: " + ex.toString()); final Throwable[] suppressedExceptions = ex.getSuppressed(); final int numSuppressed = suppressedExceptions.length; if (numSuppressed > 0) { err.println("There are " + numSuppressed + " suppressed exceptions:"); for (final Throwable exception : suppressedExceptions) { err.println("tt" + exception.toString()); } } } } }
The output for the above program will be:
Exception encountered: java.lang.NullPointerException: This exception in the close method
As you have seen, it prints only the first exception.
2. Suppressed Exceptions Support in Java 7
import static java.lang.System.err; public class ExceptionExample1 { public static void test() throws Exception { Throwable throwable = null; Resource resource = new Resource(); try { resource.use(); }catch (Exception e) { throwable = e; } finally { try{ resource.close(); }catch (Exception e){ if (throwable != null){ e.addSuppressed(throwable); throw e; } } } } public static void main(String args[]) throws Exception{ try { test(); } catch (Exception ex) { err.println("Exception encountered: " + ex.toString()); final Throwable[] suppressedExceptions = ex.getSuppressed(); final int numSuppressed = suppressedExceptions.length; if (numSuppressed > 0) { err.println("There are " + numSuppressed + " suppressed exceptions:"); for (final Throwable exception : suppressedExceptions) { err.println("" + exception.toString()); } } } } }
The output for the above program will be:
Exception encountered: java.lang.NullPointerException: This exception in the close method tThere are 1 suppressed exceptions: java.lang.RuntimeException: This exception in the use method
If you look at the above output, now we are able to get the both the exceptions from the list. First one is the primary exception and second one is the additional exception.
3. Default try-with-resource block
Here is the example code:
public class ExceptionExample { public static void main(String args[]) throws Exception{ try (Resource resource= new Resource()) { resource.use(); } } }
When you run the above program, you will see the following exceptions:
Exception in thread "main" java.lang.RuntimeException: This exception in the use method at net.infy.exception.Resource.use(Resource.java:5) at net.infy.exception.ExceptionExample1.main(ExceptionExample1.java:8) Suppressed: java.lang.NullPointerException: This exception in the close method at net.infy.exception.Resource.close(Resource.java:10) at net.infy.exception.ExceptionExample1.main(ExceptionExample1.java:9)
If you compare to the above examples, this is very clear that Java 7 has reduced much of the code and handling the automatically suppressed exceptions. If you have any questions, please write it in the comments section.