Подавляемые исключения Java с примерами

Подавленные исключения, как следует из названия, это исключения, выброшенные в коде, но каким-то образом проигнорированные. Если вы помните последовательность выполнения блока try-catch-finally и то, как они возвращают какие-либо значения или исключения, вы вспомните, что исключения, выброшенные в блоке finally, подавляются, если исключение выброшено также в блоке try.

До Java 7 вы получали информацию об этих исключениях путем регистрации, если она была реализована, но у вас не было никакого контроля над этими типами исключений после завершения блока Finally.

Что ж, с новыми возможностями Java 7 вы также получили контроль над этими подавленными исключениями.

1. Что такое подавленные исключения?

В Java 7, возможно, наиболее распространенным случаем использования подавленных исключений является оператор try-with-resources. Когда мы сталкиваемся с исключением в блоке try, приложение пытается закрыть ресурс. Если оно сталкивается с несколькими исключениями, которые могут возникнуть при закрытии ресурсов AutoCloseable, к основному исключению присоединяются дополнительные исключения в качестве подавленных исключений.

Для поддержки подавленных исключений в класс Throwable(родительский класс Exception и Error) в JDK 7 были добавлены новый конструктор и два новых метода.

Throwable.getSupressed

(); // Возвращает Throwable[]

Throwable.addSupressed

(aThrowable);

2. Пример подавленного исключения

Например, при записи в выходной поток может быть выброшено исключение из блока try, а также может быть выброшено до двух исключений из оператора try-with-resources при попытке закрыть поток.

Если исключение выбрасывается из блока try и одно или несколько исключений выбрасываются из оператора try-with-resources, то эти исключения, выброшенные из оператора try-with-resources, подавляются, а исключение, выброшенное блоком, — это исключение, выброшенное методом closeStream().

Вы можете получить эти подавленные исключения, вызвав метод Throwable.getSuppressed() из исключения, выданного блоком try.

3. Демонстрация в различных сценариях

Для примера я пишу автоматически закрываемый ресурс(т.е. DirtyResource.java), который выдает исключения, когда мы пытаемся получить к нему доступ или закрыть его. Таким образом, мы сможем увидеть разное поведение при доступе разным способом.

public class DirtyResource implements AutoCloseable{/*** Need to call this method if you want to access this resource* @throws RuntimeException no matter how you call this method* */public void accessResource(){throw new RuntimeException("I wanted to access this resource. Bad luck. Its dirty resource !!!");}/*** The overridden closure method from AutoCloseable interface* @throws Exception which is thrown during closure of this dirty resource* */@Overridepublic void close() throws Exception{throw new NullPointerException("Remember me. I am your worst nightmare !! I am Null pointer exception !!");}}

3.1. До подавления исключений

package com.howtodoinjava.demo.core;import static java.lang.System.err;public class SuppressedExceptionDemoWithTryFinallyPrevious{/*** Executable member function demonstrating suppressed exceptions* One exception is lost if not added in suppressed exceptions list*/public static void memberFunction() throws Exception{DirtyResource resource= new DirtyResource();try{resource.accessResource();}finally{resource.close();}}public static void main(String[] arguments) throws Exception{try{memberFunction();}catch(Exception ex){err.println("Exception encountered: " + ex.toString());final Throwable[] suppressedExceptions = ex.getSuppressed();final int numSuppressed = suppressedExceptions.length;if(numSuppressed > 0){err.println("tThere are " + numSuppressed + " suppressed exceptions:");for(final Throwable exception : suppressedExceptions){err.println("tt" + exception.toString());}}}}}Output:Exception encountered: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!

Как видите, было захвачено только одно исключение, а второе RuntimeException было подавлено.

3.2. Поддержка подавленных исключений в Java 7

package com.howtodoinjava.demo.core;import static java.lang.System.err;public class SuppressedExceptionDemoWithTryFinallyNew{/*** Executable member function demonstrating suppressed exceptions* Suppressed expression is added back in primary exception*/public static void memberFunction() throws Exception{Throwable th = null;DirtyResource resource= new DirtyResource();try{resource.accessResource();}catch(Exception e){th = e;}finally{try{resource.close();}catch(Exception e){if(th != null){e.addSuppressed(th); //Add to primary exceptionthrow e;}}}}/*** Executable function demonstrating suppressed exceptions.*/public static void main(String[] arguments) throws Exception{try{memberFunction();}catch(Exception ex){err.println("Exception encountered: " + ex.toString());final Throwable[] suppressedExceptions = ex.getSuppressed();final int numSuppressed = suppressedExceptions.length;if(numSuppressed > 0){err.println("tThere are " + numSuppressed + " suppressed exceptions:");for(final Throwable exception : suppressedExceptions){err.println("tt" + exception.toString());}}}}}Output:Exception encountered: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!There are 1 suppressed exceptions:java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!

Здесь, в блоке catch, мы можем получить доступ к обоим исключениям: одному как основному исключению и второму как подавленному исключению.

3.3. блок try-with-resource в функции-члене и перехват исключения

package com.howtodoinjava.demo.core;import static java.lang.System.err;public class SuppressedExceptionDemoWithTryCatch{public static void memberFunction() throws Exception{try(DirtyResource resource= new DirtyResource()){resource.accessResource();}}/*** Executable member function demonstrating suppressed exceptions using try-with-resources*/public static void main(String[] arguments) throws Exception{try{memberFunction();}catch(Exception ex){err.println("Exception encountered: " + ex.toString());final Throwable[] suppressedExceptions = ex.getSuppressed();final int numSuppressed = suppressedExceptions.length;if(numSuppressed > 0){err.println("tThere are " + numSuppressed + " suppressed exceptions:");for(final Throwable exception : suppressedExceptions){err.println("tt" + exception.toString());}}}}}Output:Exception encountered: java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!There are 1 suppressed exceptions:java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!

Отлично!! Мы можем увидеть оба исключения при использовании try-with-resource в функции-члене.

3.4 Блок try-with-resource по умолчанию

package com.howtodoinjava.demo.core;public class SuppressedExceptionDemoWithTryWithResource{/*** Demonstrating suppressed exceptions using try-with-resources*/public static void main(String[] arguments) throws Exception{try(DirtyResource resource= new DirtyResource()){resource.accessResource();}}}Output:Exception in thread "main" java.lang.RuntimeException: I wanted to access this resource. Bad luck. Its dirty resource !!!at DirtyResource.accessResource(DirtyResource.java:9)at SuppressedExceptionDemoWithTryWithResource.main(SuppressedExceptionDemoWithTryWithResource.java:12)Suppressed: java.lang.NullPointerException: Remember me. I am your worst nightmare !! I am Null pointer exception !!at DirtyResource.close(DirtyResource.java:19)at SuppressedExceptionDemoWithTryWithResource.main(SuppressedExceptionDemoWithTryWithResource.java:13)

Что ж, это действительно здорово — увидеть вывод с полной информацией, а также подавленными исключениями.

Прокрутить вверх