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
при попытке открыть несуществующий файл. Поскольку объект fileIn
никогда не был инициализирован, он выдаст исключение 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
, где метод close
создает исключение. В Java 7 появилась конструкция try-with-resources
и интерфейс AutoCloseable
для управления ресурсами.
Во-первых, давайте создадим ресурс, реализующий 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()");
}
}
Далее давайте используем наш ExceptionalResource
в блоке 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
и getSuppressed
для доступа к этим подавленным исключениям. Наконец, мы увидели, как работают подавленные исключения при использовании блока try-with-resources .
Как всегда, код примера доступен на GitHub .