Что такое AutoCloseable интерфейс?
AutoCloseable появился в Java 7 специально для try-with-resources. Closeable (Java 5) был только для I/O потоков. AutoCloseable -- в java.lang (без импортов), чтобы любой ресурс...
Junior Level
Определение
java.lang.AutoCloseable — это интерфейс с одним методом close(), который вызывается автоматически при выходе из блока try-with-resources.
AutoCloseable появился в Java 7 специально для try-with-resources. Closeable (Java 5) был только для I/O потоков. AutoCloseable – в java.lang (без импортов), чтобы любой ресурс мог стать «закрываемым».
public interface AutoCloseable {
void close() throws Exception;
}
Как использовать
// FileInputStream реализует AutoCloseable
try (FileInputStream fis = new FileInputStream("file.txt")) {
fis.read();
} // fis.close() вызовется автоматически
Какие классы его реализуют
InputStream/OutputStream— файлы, сетьConnection/Statement— база данныхReader/Writer— текстScanner— утилиты
Зачем нужен
Чтобы не забывать закрывать ресурсы. До Java 7 приходилось писать finally с close() вручную.
Middle Level
Почему в java.lang?
Это фундаментальный интерфейс. Его вынесли в java.lang, чтобы он был доступен везде без импортов — на уровне Runnable или Iterable.
Правильная реализация close()
1. Сужение типа исключения:
Интерфейс объявляет throws Exception. Переопределяйте с конкретным типом:
public class MyResource implements AutoCloseable {
@Override
public void close() throws IOException { // конкретнее
// закрытие
}
}
Или вообще без throws, если метод безопасен.
2. Паттерн “Safe Close”: Если ресурс владеет несколькими под-ресурсами:
public void close() throws Exception {
try {
subResource1.close();
} finally {
subResource2.close(); // закроется даже если первый упал
}
}
3. Идемпотентность:
Повторный вызов close() не должен выбрасывать исключение.
Garbage Collector и AutoCloseable
AutoCloseable не заменяет управление памятью. Ресурс (файл, сокет) — это нативный дескриптор в ОС. Если не вызвать close(), дескриптор “висит” пока GC не соберёт объект.
Это ведёт к ошибке “Too many open files”.
Три подхода к управлению ресурсами
| Механизм | Когда срабатывает | Гарантия | Рекомендация |
|---|---|---|---|
| TWR | При выходе из блока | ✅ Гарантирует | Основной способ |
| Cleaner | Когда GC решит | ⚠️ Страховка | Фолбэк, если забыли close() |
| finalize() | Когда GC решит | ❌ Непредсказуем | Устарел (deprecated в Java 9) |
Senior Level
Under the Hood: нативные дескрипторы
Ресурс — это не Java-объект, а дескриптор операционной системы. Дескриптор – число (int), которое ОС выдаёт при открытии файла/сокета. Java-объект – лишь обёртка. GC видит обёртку, но не видит нативный ресурс в ОС. Без явного close() дескриптор утечёт, даже если GC собрал Java-объект. GC не видит нативные ресурсы. Без close() дескриптор утекает, даже если Java-объект собран.
Atomic State в многопоточных средах
public class MyResource implements AutoCloseable {
private final AtomicBoolean closed = new AtomicBoolean(false);
public void close() {
if (closed.compareAndSet(false, true)) {
// реальное освобождение ресурсов
}
}
}
Два потока не должны закрыть один сокет одновременно — неопределённое поведение на уровне нативного драйвера.
Бросание исключений в конструкторе
Если конструктор бросил исключение после открытия нативного ресурса, но до возврата объекта — утечка:
public class MyResource implements AutoCloseable {
private final NativeHandle handle;
public MyResource(String path) {
this.handle = openNative(path); // открыли
if (!validate(path)) {
throw new IllegalArgumentException(); // handle утек!
}
}
}
Решение: лёгкие конструкторы, тяжёлое открытие — под try-with-resources.
Cleaner вместо Finalizer (Java 9+)
finalize() deprecated. Для “страховки” ресурсов используйте java.lang.ref.Cleaner:
public class MyResource implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.create();
private final Cleaner.Cleanable cleanable;
public MyResource() {
this.cleanable = cleaner.register(this, () -> {
// последний рубеж — если не вызвали close()
System.err.println("Resource not closed properly!");
});
}
public void close() {
cleanable.clean();
}
}
// Cleaner запускается GC. Когда на MyResource больше нет сильных ссылок,
// GC отмечает объект для очистки. Cleaner выполнит лямбду в отдельном потоке.
// Это НЕ замена TWR -- GC может сработать через минуты или даже часы.
// Cleaner -- страховка, если забыли close().
Это лишь страховка, не отменяющая важности TWR.
Диагностика
- SonarLint Rule — “Resources should be closed”. Проверяет иерархию типов.
jcmd VM.native_memory— мониторинг нативной памяти- Утечка дескрипторов — частая причина падения JVM через дни работы
🎯 Шпаргалка для интервью
Обязательно знать:
AutoCloseableпоявился в Java 7 специально для try-with-resources- Единственный метод:
void close() throws Exception - Находится в
java.lang— доступен без импортов, какRunnable close()должен быть идемпотентным (повторный вызов безопасен)- GC не видит нативные дескрипторы — без
close()утечка даже при собранном объекте - Сужайте
throws Exceptionдо конкретного типа или убирайте совсем Cleaner(Java 9+) — страховка, но НЕ замена TWR
Частые уточняющие вопросы:
- Почему в java.lang, а не в java.io? — Чтобы любой класс мог стать закрываемым без импортов, на уровне
Object - Что будет если не закрыть ресурс? — Утечка нативных дескрипторов → “Too many open files” → падение JVM
- Может ли close() бросить исключение? — Да, поэтому в multi-resource TWR исключения подавляются (suppressed)
- Чем Cleaner лучше finalize()? — Cleaner предсказуемее,
finalize()deprecated в Java 9
Красные флаги (НЕ говорить):
- “GC сам закроет ресурсы” — GC собирает Java-объект, но не нативный дескриптор
- “AutoCloseable только для I/O” — Это
Closeable;AutoCloseableдля любых ресурсов - “Можно не делать close() идемпотентным” — Javadoc настоятельно рекомендует, повторный вызов не должен падать
Связанные темы:
- [[12. В чём разница между AutoCloseable и Closeable]]
- [[9. Что такое try-with-resources]]
- [[10. Какие требования к ресурсам в try-with-resources]]
- [[18. Что такое оборачивание (wrapping) исключений]]
- [[22. Что произойдёт, если в блоке finally тоже возникнет исключение]]