← Назад к вопросам

Добавит ли что-то close при вызове в блок try

1.7 Middle🔥 201 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Try-with-resources и close() метод

Вопрос: Вызовется ли close() при объявлении ресурса в try?

Ответ: Да, close() вызывается автоматически.

Это называется try-with-resources (introduced в Java 7) — конструкция, которая автоматически закрывает ресурсы при выходе из блока try.

Синтаксис

// Автоматически вызовет close()
try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
    String line = reader.readLine();
    System.out.println(line);
} // ← close() вызывается здесь

Как это работает

Старый способ (Java 6 и ранее)

BufferedReader reader = null;
try {
    reader = new BufferedReader(new FileReader("file.txt"));
    String line = reader.readLine();
    System.out.println(line);
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (reader != null) {
        try {
            reader.close();  // Нужно вручную закрывать
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Проблемы:

  • Много boilerplate кода
  • Если забыть close() — утечка ресурсов
  • Сложно читать

Новый способ (Java 7+)

try (BufferedReader reader = new BufferedReader(new FileReader("file.txt"))) {
    String line = reader.readLine();
    System.out.println(line);
} catch (IOException e) {
    e.printStackTrace();
}
// close() вызывается автоматически, даже при исключении!

Преимущества:

  • Компактно
  • Безопасно (close() вызывается всегда)
  • Понятно

Когда вызывается close()

1. При нормальном выходе из блока

try (FileInputStream fis = new FileInputStream("file.txt")) {
    byte[] data = new byte[1024];
    fis.read(data);
    System.out.println("Данные прочитаны");
} // ← close() вызывается после этой скобки
// fis больше недоступен

2. При исключении

try (FileInputStream fis = new FileInputStream("nonexistent.txt")) {
    // Исключение при открытии файла
    byte[] data = new byte[1024];
} catch (FileNotFoundException e) {
    System.out.println("Файл не найден");
}
// close() вызывается, даже если было исключение

3. При раннем return

public void readFile() {
    try (FileInputStream fis = new FileInputStream("file.txt")) {
        if (someCondition()) {
            return;  // ← close() вызывается перед return
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

4. При break/continue в цикле

for (int i = 0; i < 10; i++) {
    try (Scanner scanner = new Scanner("data")) {
        if (i == 5) {
            break;  // ← close() вызывается перед break
        }
    }
}

Какие объекты поддерживают try-with-resources

Объект должен реализовать интерфейс AutoCloseable:

public interface AutoCloseable {
    void close() throws Exception;
}

Встроенные классы

// Все эти классы имплементируют AutoCloseable

// Потоки
FileInputStream
FileOutputStream
FileReader
FileWriter
BufferedReader
BufferedWriter
Scanner

// БД
Connection
Statement
ResultSet

// Сетевые
Socket
ServerSocket
DatagramSocket

// Другое
PrintWriter
ZipFile
Timer

Пример 1: Работа с файлами

public class FileExample {
    public static void main(String[] args) {
        // Чтение файла
        try (BufferedReader reader = new BufferedReader(
                new FileReader("input.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // reader.close() уже вызвана
    }
}

Пример 2: Работа с БД

public class DatabaseExample {
    public void executeQuery() {
        // Try-with-resources для Connection и Statement
        try (Connection conn = DriverManager.getConnection(url, user, pass);
             Statement stmt = conn.createStatement()) {
            
            ResultSet rs = stmt.executeQuery("SELECT * FROM users");
            while (rs.next()) {
                System.out.println(rs.getString("name"));
            }
            // rs НЕ автоматически закрывается (не реализует AutoCloseable)
            
        } catch (SQLException e) {
            e.printStackTrace();
        }
        // conn.close() и stmt.close() уже вызваны
    }
}

Лучше с try-with-resources для ResultSet

public void executeQuery() {
    try (Connection conn = DriverManager.getConnection(url, user, pass);
         Statement stmt = conn.createStatement();
         ResultSet rs = stmt.executeQuery("SELECT * FROM users")) {
        
        while (rs.next()) {
            System.out.println(rs.getString("name"));
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }
    // Все закрыто: rs, stmt, conn
}

Пример 3: Несколько ресурсов

public void copyFile(String from, String to) {
    // Можно объявить несколько ресурсов
    try (FileInputStream fis = new FileInputStream(from);
         FileOutputStream fos = new FileOutputStream(to)) {
        
        byte[] buffer = new byte[1024];
        int length;
        while ((length = fis.read(buffer)) > 0) {
            fos.write(buffer, 0, length);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
    // fis.close() и fos.close() вызваны в обратном порядке
    // (LIFO - Last In First Out)
}

Порядок закрытия ресурсов

Ресурсы закрываются в обратном порядке их объявления (LIFO):

try (Resource1 r1 = new Resource1();
     Resource2 r2 = new Resource2();
     Resource3 r3 = new Resource3()) {
    // Использование ресурсов
}
// Порядок закрытия:
// 1. r3.close()
// 2. r2.close()
// 3. r1.close()

Исключения при close()

Что если close() выбросит исключение?

try (MyResource resource = new MyResource()) {
    resource.use();
} catch (Exception e) {
    System.out.println("Поймали: " + e.getMessage());
}

Если и use(), и close() выбросят исключения:

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

// Какое исключение будет поймано?
try (MyResource r = new MyResource()) {
    r.use();  // Выбросит Exception("Ошибка при use()")
} catch (Exception e) {
    System.out.println(e.getMessage());  // "Ошибка при use()"
    // Исключение от close() станет "suppressed"
    for (Throwable suppressed : e.getSuppressed()) {
        System.out.println("Подавленное: " + suppressed.getMessage());
        // "Ошибка при close()"
    }
}

Как это компилируется

Try-with-resources — это синтаксический сахар. Компилятор превращает его в что-то вроде:

// Исходный код
try (Resource r = new Resource()) {
    r.use();
} catch (Exception e) {
    e.printStackTrace();
}

// Что генерирует компилятор (примерно)
Resource r = new Resource();
Try {
    r.use();
} catch (Exception e) {
    e.printStackTrace();
} finally {
    if (r != null) {
        r.close();
    }
}

Создание собственного AutoCloseable

public class DatabaseConnection implements AutoCloseable {
    private Connection connection;
    
    public DatabaseConnection(String url, String user, String password) {
        try {
            this.connection = DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    
    public void executeQuery(String sql) throws SQLException {
        try (Statement stmt = connection.createStatement()) {
            stmt.executeUpdate(sql);
        }
    }
    
    @Override
    public void close() throws Exception {
        if (connection != null && !connection.isClosed()) {
            connection.close();
            System.out.println("Соединение с БД закрыто");
        }
    }
}

// Использование
public void test() {
    try (DatabaseConnection db = new DatabaseConnection(url, user, pass)) {
        db.executeQuery("UPDATE users SET name=Alice");
    } catch (Exception e) {
        e.printStackTrace();
    }
    // db.close() вызвана автоматически
}

Плюсы try-with-resources

  1. Автоматическое закрытие — не нужно помнить про finally
  2. Безопасность — close() вызывается даже при исключении
  3. Порядок закрытия — ресурсы закрываются в правильном порядке
  4. Подавленные исключения — если при close() есть ошибка, она не потеряется
  5. Читаемость — меньше кода

Минусы / Ограничения

  1. Только для AutoCloseable — обычные объекты не поддерживаются
  2. Java 7+ — не работает на более старых версиях
  3. close() может выбросить исключение — нужно обрабатывать

Когда использовать

✓ Файловый ввод-вывод ✓ Подключения к БД ✓ Сетевые сокеты ✓ Любой ресурс, реализующий AutoCloseable ✓ Несколько ресурсов одновременно

Вывод

Try-with-resources — это важная фич Java для управления ресурсами. Она автоматически вызывает close() при выходе из блока, что предотвращает утечки ресурсов. Это обязательный паттерн для работы с файлами, БД и сетевыми подключениями.

Добавит ли что-то close при вызове в блок try | PrepBro