Что такое подавленные исключения (Suppressed Exceptions) в Java?

«Что такое подавленные исключения (Suppressed Exceptions) в Java?» — вопрос из категории Java Core, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Подавленные исключения (Suppressed Exceptions) — это механизм в Java (начиная с версии 7), который позволяет связать с основным исключением дополнительные исключения, возникшие в процессе его обработки, например, в блоке try-with-resources при закрытии ресурсов.

Зачем это нужно? Без этого механизма при возникновении исключения в try-блоке и последующем исключении в close() методе ресурса, информация о втором исключении была бы потеряна, так как в JVM может быть «активно» только одно исключение.

Как это работает:

  • Исключение, возникшее первым (обычно в try-блоке), становится основным (primary).
  • Исключения, возникшие позже (например, при закрытии ресурсов в finally или try-with-resources), добавляются к основному с помощью метода Throwable.addSuppressed(Throwable).
  • Получить массив подавленных исключений можно с помощью метода Throwable.getSuppressed().

Пример с try-with-resources:

class FailingResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
        throw new IOException("Ошибка при закрытии ресурса"); // Подавленное исключение
    }
}

public class SuppressedExample {
    public static void main(String[] args) {
        try (FailingResource res = new FailingResource()) {
            throw new RuntimeException("Ошибка в основном блоке try"); // Основное исключение
        } catch (Exception e) {
            System.out.println("Поймано: " + e.getMessage()); // Основное исключение
            System.out.println("Подавленные исключения:");
            for (Throwable t : e.getSuppressed()) {
                System.out.println("t- " + t.getMessage()); // Исключение из close()
            }
        }
    }
}
// Вывод:
// Поймано: Ошибка в основном блоке try
// Подавленные исключения:
//     - Ошибка при закрытии ресурса

Другие сценарии:

  • CompletableFuture: Метод CompletableFuture.get() может выбросить ExecutionException, причиной (getCause()) которого будет первое из возникших исключений. Остальные исключения из других этапов цепочки могут быть потеряны, если не собраны вручную.
  • Ручное добавление: Вы можете использовать этот механизм в своих обработчиках ошибок, чтобы не терять контекст.

Важность: Этот механизм обеспечивает полное протоколирование ошибок в сложных сценариях, особенно при работе с ресурсами, что критично для отладки.