Menu
Coddy logo textTech

Паттерн Try With Resources

Часть раздела Объектно-ориентированное программирование путешествия по Java на Coddy. Урок 62 из 87.

При работе с ресурсами, такими как потоки file или соединения с базой данных connection, необходимо всегда закрывать их после завершения работы. В противном случае вы рискуете столкнуться с утечками памяти. Традиционный approach использует блок finally, но он многословен и подвержен ошибкам.

Инструкция try-with-resources в Java автоматически закрывает ресурсы, когда блок завершается. Любой класс, который реализует интерфейс AutoCloseable, можно использовать с этим синтаксисом:

// Традиционный подход — многословный и рискованный
BufferedReader reader = null;
try {
    reader = new BufferedReader(new FileReader("file.txt"));
    String line = reader.readLine();
} finally {
    if (reader != null) {
        reader.close();  // Также может выбросить исключение!
    }
}

// Try-with-resources — чистый и безопасный
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
    String line = reader.readLine();
}  // Автоматически закрывается здесь

Вы можете управлять несколькими ресурсами, разделяя их точками с запятой. Они закрываются в обратном порядке объявления:

try (FileReader fr = new FileReader("input.txt");
     BufferedReader br = new BufferedReader(fr)) {
    // Используем оба ресурса
}  // br закрывается первым, затем fr

Чтобы создать собственный автоматически закрываемый класс, реализуйте интерфейс AutoCloseable и его единственный метод close():

public class DatabaseConnection implements AutoCloseable {
    public DatabaseConnection() {
        System.out.println("Connection opened");
    }
    
    @Override
    public void close() {
        System.out.println("Connection closed");
    }
}

Этот шаблон гарантирует, что ресурсы всегда корректно освобождаются, даже если во время обработки возникают исключения.

challenge icon

Задание

Легко

Давайте создадим систему управления ресурсами, которая демонстрирует возможности try-with-resources! Вы создадите пользовательские auto-closeable классы, имитирующие управление соединениями и сессиями, гарантируя их корректное закрытие.

Вы организуете код в трёх файлах:

  • Connection.java: Создайте class, имитирующий соединение с базой данных. Ваш class Connection должен реализовывать AutoCloseable. В нём должно быть private поле для имени соединения (String), constructor, принимающий имя и выводящий [name] connection opened, method query(String sql), выводящий Executing on [name]: [sql], и обязательный method close(), выводящий [name] connection closed.
  • Session.java: Создайте ещё один auto-closeable class, имитирующий пользовательскую сессию. Ваш class Session также должен реализовывать AutoCloseable. Добавьте private поле для имени пользователя (String), constructor, принимающий имя пользователя и выводящий Session started for [username], method performAction(String action), выводящий [username] performed: [action], и method close(), выводящий Session ended for [username].
  • Main.java: Объедините систему управления ресурсами! Вы получите три входных значения: имя соединения, имя пользователя и action для выполнения.

    Сначала продемонстрируйте управление одним ресурсом. Выведите === Single Resource ===, затем с помощью try-with-resources создайте Connection с заданным именем. Внутри блока try вызовите query("SELECT * FROM users"). Соединение должно автоматически закрыться, когда блок завершится.

    Затем продемонстрируйте работу с несколькими ресурсами. Выведите пустую строку, затем === Multiple Resources ===. Используйте try-with-resources одновременно с Connection (с тем же именем) и Session (с именем пользователя), объявив их в этом порядке и разделив точками с запятой. Внутри блока try сначала вызовите query("INSERT INTO logs") для соединения, затем вызовите performAction с входным action для сессии. Обратите внимание, как ресурсы закрываются в обратном порядке!

Вы получите три входных значения в следующем порядке: имя соединения (String), имя пользователя (String) и action (String).

Обратите внимание, как try-with-resources устраняет необходимость в явных вызовах close и блоках finally. Ресурсы гарантированно закрываются даже в случае возникновения исключений, а несколько ресурсов закрываются в обратном порядке объявления!

Попробуйте сами

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String connectionName = scanner.nextLine();
        String username = scanner.nextLine();
        String action = scanner.nextLine();
        
        // === Single Resource ===
        // TODO: Выведите заголовок
        // TODO: Используйте try-with-resources для создания Connection
        // TODO: Inside the try block, call query("SELECT * FROM users")
        
        // === Multiple Resources ===
        // TODO: Выведите пустую строку и заголовок
        // TODO: Используйте try-with-resources с Connection и Session
        // TODO: Внутри блока try:
        //       - Call query("INSERT INTO logs") on the connection
        //       - Вызовите performAction с входным action на session
        
    }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Java