Автор оригинала: Amy DeGregorio.
1. введение
В этом кратком руководстве мы узнаем о подавленных исключениях в Java. Короче говоря, подавленное исключение-это исключение, которое выбрасывается, но каким-то образом игнорируется. Распространенный сценарий для этого в Java-это когда блок finally создает исключение. Любое исключение, первоначально возникшее в блоке try , затем подавляется.
Начиная с Java 7, теперь мы можем использовать два метода в классе Throwable для обработки подавленных исключений: addSuppressed и getSuppressed . Следует отметить, что конструкция try-with-resources также была введена в Java 7. В наших примерах мы увидим, как они связаны.
2. Подавленные исключения в действии
2.1. Сценарий Подавленного исключения
Давайте начнем с быстрого рассмотрения примера, в котором исходное исключение подавляется исключением, возникающим в блоке finally :
public static void demoSuppressedException(String filePath) throws IOException { FileInputStream fileIn = null; try { fileIn = new FileInputStream(filePath); } catch (FileNotFoundException e) { throw new IOException(e); } finally { fileIn.close(); } }
Пока мы указываем путь к существующему файлу, никаких исключений не будет, и метод будет работать так, как ожидалось.
Однако предположим, что мы предоставляем файл, который не существует:
@Test(expected = NullPointerException.class) public void givenNonExistentFileName_whenAttemptFileOpen_thenNullPointerException() throws IOException { demoSuppressedException("/non-existent-path/non-existent-file.txt"); }
В этом случае блок try вызовет исключение FileNotFoundException при попытке открыть несуществующий файл. Поскольку файл В объекте никогда не был инициализирован, он вызовет исключение NullPointerException , когда мы попытаемся закрыть его в нашем блоке finally . Наш вызывающий метод получит только исключение NullPointerException , и будет не совсем очевидно, в чем заключалась первоначальная проблема: что файл не существует.
2.2. Добавление Подавленного Исключения
Теперь давайте посмотрим, как мы можем воспользоваться преимуществами метода Throwable.addSuppressed для предоставления исходного исключения:
public static void demoAddSuppressedException(String filePath) throws IOException { Throwable firstException = null; FileInputStream fileIn = null; try { fileIn = new FileInputStream(filePath); } catch (IOException e) { firstException = e; } finally { try { fileIn.close(); } catch (NullPointerException npe) { if (firstException != null) { npe.addSuppressed(firstException); } throw npe; } } }
Давайте перейдем к нашему модульному тесту и посмотрим, как getSuppressed работает в этой ситуации:
try { demoAddSuppressedException("/non-existent-path/non-existent-file.txt"); } catch (Exception e) { assertThat(e, instanceOf(NullPointerException.class)); assertEquals(1, e.getSuppressed().length); assertThat(e.getSuppressed()[0], instanceOf(FileNotFoundException.class)); }
Теперь у нас есть доступ к этому исходному исключению из массива подавленных исключений.
2.3. Использование try-with-resources
Наконец, давайте рассмотрим пример использования try-with-resources , где метод close вызывает исключение. Java 7 представила конструкцию try-with-resources и интерфейс AutoCloseable для управления ресурсами.
Во-первых, давайте создадим ресурс, который реализует Автоклавируемый :
public class ExceptionalResource implements AutoCloseable { public void processSomething() { throw new IllegalArgumentException("Thrown from processSomething()"); } @Override public void close() throws Exception { throw new NullPointerException("Thrown from close()"); } }
Далее, давайте используем наш Исключительный ресурс в блоке try-with-resources :
public static void demoExceptionalResource() throws Exception { try (ExceptionalResource exceptionalResource = new ExceptionalResource()) { exceptionalResource.processSomething(); } }
Наконец, давайте перейдем к нашему модульному тесту и посмотрим, как вытрясаются исключения:
try { demoExceptionalResource(); } catch (Exception e) { assertThat(e, instanceOf(IllegalArgumentException.class)); assertEquals("Thrown from processSomething()", e.getMessage()); assertEquals(1, e.getSuppressed().length); assertThat(e.getSuppressed()[0], instanceOf(NullPointerException.class)); assertEquals("Thrown from close()", e.getSuppressed()[0].getMessage()); }
Следует отметить, что при использовании AutoCloseable , это исключение, вызванное в методе close , которое подавляется . Возникает исходное исключение.
3. Заключение
В этом коротком уроке мы узнали, что такое подавленные исключения и как они происходят. Затем мы увидели, как использовать методы addSuppressed и get Suppressed для доступа к этим подавленным исключениям. Наконец, мы увидели, как работают подавленные исключения при использовании блока try-with-resources .
Как всегда, пример кода доступен на GitHub .