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

Любой ли экземпляр класса закроется при размещении в скобках блока try

1.3 Junior🔥 211 комментариев
#ООП

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

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

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

Try-with-resources: условие автоматического закрытия ресурсов

Основной ответ

НЕТ, не любой экземпляр класса закроется при размещении в скобках блока try. Закроется только тот, который реализует интерфейс AutoCloseable (или его подинтерфейс Closeable).

Механизм try-with-resources

Тry-with-resources (введён в Java 7) — это синтаксический сахар для автоматического управления ресурсами:

// ✓ Правильно: InputStream реализует AutoCloseable
try (InputStream is = new FileInputStream("file.txt")) {
    // Работа с потоком
    byte[] data = is.readAllBytes();
} // is.close() вызовется автоматически

// ❌ ОШИБКА КОМПИЛЯЦИИ: String не реализует AutoCloseable
try (String text = "hello") {  // Compilation error!
    // String.close() не существует
}

Интерфейс AutoCloseable

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

Любой класс, реализующий этот интерфейс, может использоваться в try-with-resources.

Примеры правильного использования

1. Работа с файлами

// ✓ Закроется автоматически
try (FileInputStream fis = new FileInputStream("input.txt");
     FileOutputStream fos = new FileOutputStream("output.txt")) {
    
    byte[] buffer = new byte[1024];
    int bytesRead;
    while ((bytesRead = fis.read(buffer)) != -1) {
        fos.write(buffer, 0, bytesRead);
    }
} // Оба потока закроются в обратном порядке

2. Работа с БД

// ✓ Connection и Statement реализуют AutoCloseable
try (Connection conn = DriverManager.getConnection(url, user, pass);
     Statement stmt = conn.createStatement()) {
    
    ResultSet rs = stmt.executeQuery("SELECT * FROM users");
    while (rs.next()) {
        String name = rs.getString("name");
        System.out.println(name);
    }
} // Connection и Statement закроются автоматически

Пользовательский класс с AutoCloseable

public class DatabaseConnection implements AutoCloseable {
    private Connection connection;
    
    public DatabaseConnection(String url) throws SQLException {
        this.connection = DriverManager.getConnection(url);
    }
    
    public void executeQuery(String sql) throws SQLException {
        // Выполнение запроса
    }
    
    @Override
    public void close() throws Exception {
        System.out.println("Closing database connection");
        if (connection != null && !connection.isClosed()) {
            connection.close();
        }
    }
}

// Использование
try (DatabaseConnection db = new DatabaseConnection("jdbc:mysql://localhost/mydb")) {
    db.executeQuery("SELECT * FROM users");
} // close() вызовется автоматически

Эквивалент без try-with-resources

// Что происходит под капотом
InputStream is = new FileInputStream("file.txt");
Try:
    // работа с ресурсом
Catch:
    // обработка исключений
Finally:
    is.close();  // Гарантированно вызовется

Тry-with-resources компилируется в примерно следующий код:

InputStream is = new FileInputStream("file.txt");
Try:
    // работа
Catch (Throwable t) {
    try {
        is.close();  // Закрытие при исключении
    } catch (Throwable suppressed) {
        t.addSuppressed(suppressed);  // Подавленные исключения
    }
    throw t;
}
Finally {
    if (is != null) {
        is.close();  // Закрытие в нормальном потоке
    }
}

Множество ресурсов

// ✓ Несколько ресурсов в одном try
try (FileReader fr = new FileReader("input.txt");
     BufferedReader br = new BufferedReader(fr);
     FileWriter fw = new FileWriter("output.txt");
     BufferedWriter bw = new BufferedWriter(fw)) {
    
    String line;
    while ((line = br.readLine()) != null) {
        bw.write(line.toUpperCase());
        bw.newLine();
    }
} // Все ресурсы закроются в обратном порядке

Suppressed Exceptions (подавленные исключения)

public class BadResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
        throw new IOException("Error closing resource");
    }
}

public class BuggyResource implements AutoCloseable {
    @Override
    public void close() throws Exception {
        throw new IOException("Error in close");
    }
}

// Использование
try (BadResource bad = new BadResource();
     BuggyResource buggy = new BuggyResource()) {
    
    throw new RuntimeException("Main operation failed");
} catch (Exception e) {
    System.out.println("Primary exception: " + e.getMessage());
    
    // Suppressed exceptions (подавленные)
    Throwable[] suppressed = e.getSuppressed();
    for (Throwable t : suppressed) {
        System.out.println("Suppressed: " + t.getMessage());
    }
}

// Вывод:
// Primary exception: Main operation failed
// Suppressed: Error in close (BuggyResource закрылся последним)
// Suppressed: Error closing resource (BadResource закрылся первым)

Что НЕ будет закрыто

public class PlainClass {  // ❌ Не реализует AutoCloseable
    public void cleanup() {
        System.out.println("Cleaning up");
    }
}

// Это не скомпилируется!
try (PlainClass obj = new PlainClass()) {
    // Compilation error: PlainClass does not implement AutoCloseable
}

// Правильно — без try-with-resources
PlainClass obj = new PlainClass();
try {
    // работа
} finally {
    obj.cleanup();  // Вручную
}

Проверка наличия AutoCloseable

// Узнать, реализует ли класс AutoCloseable
public boolean isAutoCloseable(Class<?> clazz) {
    return AutoCloseable.class.isAssignableFrom(clazz);
}

// Примеры
isAutoCloseable(FileInputStream.class);  // true
isAutoCloseable(String.class);            // false
isAutoCloseable(Connection.class);        // true

Best Practices

Используй try-with-resources для всех ресурсов, реализующих AutoCloseable
Добавляй AutoCloseable в свои классы, если они управляют ресурсами
Гарантируй идемпотентность close() — может вызваться несколько раз
Не выбрасывай исключения из close() без необходимости
Используй try-with-resources для нескольких ресурсов вместо вложенности

Вывод

Тry-with-resources закроет только те объекты, которые реализуют интерфейс AutoCloseable. Это касается всех стандартных ресурсов Java (потоки, соединения, файлы), но не обычных классов, даже если у них есть метод close() без интерфейса.