try-with-resources

Конструкция try-with-resources, появившаяся в Java 7, гарантирует автоматическое закрытие любого ресурса, реализующего интерфейс AutoCloseable (или его подинтерфейс Closeable). Это избавляет программиста от шаблонного кода в finally, где раньше приходилось проверять null и ловить исключения при закрытии.

Ресурс, объявленный в круглых скобках после try, закрывается автоматически после выхода из блока — независимо от того, завершился ли блок нормально или с исключением. Если ресурс бросает исключение при закрытии, оно становится «подавленным» (suppressed) и доступно через Throwable.getSuppressed().

С Java 9 разрешено использовать в скобках уже существующие effectively final переменные — не обязательно объявлять ресурс прямо внутри try.

Синтаксис

try (Resource1 r1 = new Resource1();
     Resource2 r2 = new Resource2()) {
    // работа с r1, r2
} catch (Exception e) {
    // обработка
}
// r2 и r1 уже закрыты (в обратном порядке)

Пример 1. Чтение файла

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class ReadFile {
    public static void main(String[] args) {
        try (BufferedReader br = new BufferedReader(new FileReader("sensors.log"))) {
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("Ошибка чтения: " + e.getMessage());
        }
    }
}

Output (если файла нет):

Ошибка чтения: sensors.log (No such file or directory)

Пример 2. Несколько ресурсов

import java.io.*;

public class CopyFile {
    public static void main(String[] args) {
        try (FileInputStream  in  = new FileInputStream("source.txt");
             FileOutputStream out = new FileOutputStream("dest.txt")) {
            byte[] buf = new byte[1024];
            int n;
            while ((n = in.read(buf)) != -1) {
                out.write(buf, 0, n);
            }
            System.out.println("Файл скопирован");
        } catch (IOException e) {
            System.out.println("I/O: " + e.getMessage());
        }
    }
}

Output (если source.txt отсутствует):

I/O: source.txt (No such file or directory)

Пример 3. Свой AutoCloseable

class FakeSensor implements AutoCloseable {
    private final String name;
    public FakeSensor(String name) {
        this.name = name;
        System.out.println("Открыли " + name);
    }
    public int read() {
        return 42;
    }
    @Override
    public void close() {
        System.out.println("Закрыли " + name);
    }
}

public class ResourceDemo {
    public static void main(String[] args) {
        try (FakeSensor s = new FakeSensor("DHT22")) {
            System.out.println("Чтение: " + s.read());
        }
    }
}

Output:

Открыли DHT22
Чтение: 42
Закрыли DHT22

Пример 4. Порядок закрытия

class Step implements AutoCloseable {
    private final String name;
    public Step(String name) {
        this.name = name;
        System.out.println("OPEN  " + name);
    }
    @Override
    public void close() {
        System.out.println("CLOSE " + name);
    }
}

public class OrderDemo {
    public static void main(String[] args) {
        try (Step a = new Step("A");
             Step b = new Step("B");
             Step c = new Step("C")) {
            System.out.println("work");
        }
    }
}

Output:

OPEN  A
OPEN  B
OPEN  C
work
CLOSE C
CLOSE B
CLOSE A

Пример 5. Подавленные исключения

class BadResource implements AutoCloseable {
    @Override
    public void close() {
        throw new RuntimeException("Ошибка при close()");
    }
}

public class SuppressedDemo {
    public static void main(String[] args) {
        try (BadResource r = new BadResource()) {
            throw new RuntimeException("Ошибка в try");
        } catch (RuntimeException e) {
            System.out.println("Основная: " + e.getMessage());
            for (Throwable s : e.getSuppressed()) {
                System.out.println("Подавлена: " + s.getMessage());
            }
        }
    }
}

Output:

Основная: Ошибка в try
Подавлена: Ошибка при close()

Подводные камни

Предупреждение

  • Ресурсы закрываются в обратном порядке объявления.

  • Исключение из ``close()`` становится подавленным, если уже было исключение из try.

  • ``AutoCloseable.close()`` может бросать Exception, Closeable.close() — только IOException. Выбирайте подходящий интерфейс.

  • Идиома Java 9+ позволяет использовать готовую переменную, но она должна быть effectively final.

  • Не забывайте про сам ``catch`` — try-with-resources автоматически закроет ресурс, но не обработает исключение за вас.

См. также

Примечание

Материал подготовлен на основе официальной документации Oracle Java Tutorials — The try-with-resources Statement (Oracle Free Documentation License). Текст переведён и переработан, примеры кода написаны заново.