Что такое try-with-resources и как правильно закрывать ресурсы?
try-with-resources — это конструкция языка Java (Java 7+), которая автоматически закрывает ресурсы, реализующие интерфейс AutoCloseable, при выходе из блока try.
Аналогия из жизни: try-with-resources — это как автоматическое выключение света при выходе из комнаты. Вы не забудете выключить свет (закрыть ресурс), даже если уходите в спешке (исключение в try-блоке).
AutoCloseable и Closeable
Пример
public interface AutoCloseable {
void close() throws Exception;
}
public interface Closeable extends AutoCloseable {
void close() throws IOException;
}
Все потоки IO (InputStream, OutputStream, Reader, Writer), каналы NIO (Channel), соединения с БД (Connection, Statement, ResultSet) реализуют один из этих интерфейсов.
Базовый синтаксис
Пример
// До Java 7 — громоздко и подвержено ошибкам
InputStream is = null;
try {
is = new FileInputStream("file.txt");
// чтение
} finally {
if (is != null) { is.close(); } // может поглотить исключение из try
}
// Java 7+ — лаконично и безопасно
try (InputStream is = new FileInputStream("file.txt")) {
// чтение
} // is.close() вызывается автоматически
Несколько ресурсов
Ресурсы закрываются в обратном порядке объявления:
Пример
try (FileInputStream fis = new FileInputStream("input.txt");
BufferedInputStream bis = new BufferedInputStream(fis);
FileOutputStream fos = new FileOutputStream("output.txt")) {
bis.transferTo(fos);
}
// Порядок закрытия: fos -> bis -> fis
Effectively final переменные (Java 9+)
Пример
BufferedReader reader = new BufferedReader(new FileReader("file.txt"));
try (reader) { // reader — effectively final
String line = reader.readLine();
}
Подавленные исключения (Suppressed Exceptions)
Если исключение возникает и в блоке try, и в методе close(), исключение из close() подавляется и добавляется к основному:
Пример
try (ProblematicResource resource = new ProblematicResource()) {
resource.doWork(); // бросает RuntimeException
} catch (RuntimeException e) {
e.getSuppressed(); // содержит исключение из close()
}
Частые ошибки
- Забывают, что
StreamотFiles.lines()тоже реализуетAutoCloseableи требуетtry-with-resources. - Закрывают обёртку и внутренний поток отдельно — при закрытии обёртки (BufferedInputStream) внутренний поток закрывается автоматически.
- Используют
try-with-resourcesбезcatchи считают, что исключения обработаны — конструкция только закрывает ресурсы, но не обрабатывает исключения. - В старом коде с
finallyисключение вclose()может поглотить основное исключение изtry.
На собеседовании: объясните механизм: ресурсы реализуют AutoCloseable, закрываются автоматически при выходе из try, в обратном порядке объявления. Упомяните suppressed exceptions и effectively final (Java 9+).