Ответ
Исключение в finally "перекрывает" исключения из try/catch блоков.
Основное поведение:
try {
throw new RuntimeException("Ошибка в try");
} finally {
throw new RuntimeException("Ошибка в finally");
}
// Будет выброшено: RuntimeException("Ошибка в finally")
// Оригинальное исключение из try будет подавлено (suppressed)
Механизм suppressed исключений (Java 7+):
try {
throw new IOException("Ошибка в try");
} finally {
RuntimeException finallyEx = new RuntimeException("Ошибка в finally");
finallyEx.addSuppressed(e); // Явное добавление
throw finallyEx;
}
Try-with-resources автоматически добавляет suppressed:
try (AutoCloseable resource = new MyResource()) {
throw new IOException("Ошибка в try");
}
// Если и close(), и try блок выбрасывают исключения,
// исключение из try будет основным, а из close() - suppressed
Best Practices:
-
Избегайте операций, которые могут выбросить исключения, в finally
-
Обрабатывайте исключения внутри finally:
try { // основной код } finally { try { // код очистки } catch (Exception e) { // логирование, но не проброс log.error("Ошибка в finally", e); } } -
Используйте try-with-resources для AutoCloseable ресурсов
-
Сохраняйте оригинальное исключение:
Exception mainException = null; try { // код, который может выбросить исключение } catch (Exception e) { mainException = e; throw e; } finally { try { // очистка } catch (Exception finallyEx) { if (mainException != null) { finallyEx.addSuppressed(mainException); } throw finallyEx; } }