Получить доступ

Управление ресурсами: try-with-resources

Беды ручного finally, автозакрытие AutoCloseable, suppressed-исключения и разница Closeable/AutoCloseable.

Беды ручного finally

До Java 7 ресурсы (файлы, соединения, потоки) закрывали в finally. Это многословно, требует вложенных try для нескольких ресурсов и легко ошибиться: если close() в finally сам бросит исключение, оно ЗАТРЁТ исходное исключение из тела try — и настоящая первопричина потеряется.

Плюс типичная ловушка: если ресурс не создался (исключение в инициализации), переменная остаётся null, и close() в finally даёт ещё и NullPointerException.

try-with-resources

try-with-resources автоматически закрывает всё, что реализует AutoCloseable, объявленное в круглых скобках try — гарантированно, даже при исключении или return в теле. Это убирает boilerplate и весь класс ошибок ручного закрытия.

Никогда не «глотайте» исключение пустым catch — это прячет ошибки и усложняет отладку.

try (var in = Files.newInputStream(path);
     var out = Files.newOutputStream(dst)) {
    in.transferTo(out);          // оба ресурса закроются автоматически,
} catch (IOException e) {         // out — раньше in (обратный порядок)
    throw new UncheckedIOException(e);
}

Suppressed-исключения

try-with-resources решает проблему «затирания»: если исключение бросает И тело try, И close(), то основным остаётся исключение из тела, а исключение из close() не теряется — оно прикрепляется к основному как suppressed и доступно через Throwable.getSuppressed().

Это противоположно поведению ручного finally (где побеждало исключение из close). В stack trace такие добавки печатаются с пометкой «Suppressed:» — первопричина видна.

Throwable[] suppressed = primary.getSuppressed(); // что бросили close() при раскрутке

Несколько ресурсов и порядок

Ресурсы закрываются в порядке, ОБРАТНОМ объявлению (последний открытый закрывается первым) — это логично для зависимых ресурсов (Writer поверх OutputStream).

С Java 9 в try-with-resources можно перечислять уже существующие effectively final переменные, а не только объявлять новые на месте: try (resource) { ... }.

AutoCloseable против Closeable

AutoCloseable — базовый интерфейс с единственным методом close() throws Exception; его достаточно для участия в try-with-resources. Closeable (из java.io) — его наследник, у которого close() throws более узкое IOException и по контракту должен быть идемпотентным (повторный close безвреден).

Свой ресурс делают AutoCloseable; close() желательно делать идемпотентным и по возможности не бросающим — исключение из close усложняет жизнь вызывающим.

Как отвечать на собеседовании

Объясните, чем плох ручной finally (затирание исходного исключения, NPE на null-ресурсе), как try-with-resources закрывает AutoCloseable в обратном порядке, и главное — механизм suppressed-исключений (исключение из close прикрепляется, а не затирает; getSuppressed). Различите AutoCloseable (Exception, общий) и Closeable (IOException, идемпотентный).

Вопросы по теме

Читайте также

Закрытая бета

Знать тему — половина дела

На живом собеседовании sotto слышит вопрос интервьюера и показывает короткий ответ и план. Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем