Рубрики
Без рубрики

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

Узнайте о подавленных исключениях в Java и о том, как с ними работать.

Автор оригинала: 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 .