Что гарантирует интерфейс AutoCloseable относительно повторного вызова close()?
AutoCloseable не гарантирует идемпотентность close(): повторный вызов может иметь видимые последствия или завершиться исключением. Поэтому конкретный ресурс должен явно документировать поведение повторного закрытия, а при проектировании обычно предпочтительно сделать close() безопасным при повторном вызове.
AutoCloseable появился в Java 7 вместе с механизмом try-with-resources. Он решил проблему гарантированного освобождения ресурсов при нормальном завершении блока и при возникновении исключения.
Интерфейс намеренно сделан общим: его могут реализовывать файловые дескрипторы, сетевые соединения, транзакционные объекты и другие ресурсы. У таких объектов нет единого естественного поведения при повторном закрытии, поэтому Java не навязывает идемпотентность на уровне интерфейса.
Повторный вызов close() может произойти из-за ручного закрытия ресурса, повторной передачи объекта в управляющий код или ошибки в жизненном цикле обёрток. Если метод не рассчитан на это, возможны вторичные исключения, повреждение состояния ресурса или маскирование исходной ошибки.
Особенно опасно, когда первый вызов close() уже освободил внешний ресурс, а второй обращается к недействительному дескриптору. Код, который безоговорочно предполагает идемпотентность всех AutoCloseable, некорректен.
Контракт AutoCloseable.close() допускает проверяемое исключение Exception и не требует, чтобы повторный вызов был безопасным. Это отличает его от Closeable, для которого документация ожидает идемпотентное закрытие.
При реализации собственного ресурса обычно используют состояние закрытия: первый вызов освобождает ресурс и помечает объект закрытым, последующие вызовы ничего не делают либо возвращают предсказуемый результат. Если повторное закрытие действительно является ошибкой, это нужно явно указать в документации и согласовать с вызывающим кодом.
Идемпотентность не означает, что close() обязан молча игнорировать любые проблемы. Ошибка освобождения, возникшая во время первого вызова, должна быть обработана по правилам конкретного ресурса; безопасный повторный вызов не должен скрывать эту первоначальную ошибку.
Проверка состояния делает повторное закрытие предсказуемым. Однако синхронизация и видимость поля closed становятся отдельной задачей, если ресурс используется из нескольких потоков.
В приложении есть адаптер соединения с внешним сервисом. Один слой закрывает его в try-with-resources, а другой слой в обработчике отмены также пытается освободить соединение.
Вариант с исключением при повторном close() позволяет обнаруживать ошибки жизненного цикла, но может замаскировать исходную ошибку операции. Вариант с безусловным повторным освобождением внешнего дескриптора проще, но способен привести к ошибкам доступа к уже закрытому ресурсу.
Выбран вариант с идемпотентным close(), синхронизацией состояния и отдельным логированием первой ошибки освобождения. Это соответствует ожиданиям большинства управляющих конструкций, делает отмену безопасной и не превращает повторное завершение в новую аварию.
try-with-resources сам проверять, закрыт ли ресурс до вызова close()?Нет. Механизм вызывает close() согласно правилам управления ресурсами, но не знает внутреннего состояния объекта и не добавляет универсальную проверку закрытости. Ответственность за корректное повторное закрытие лежит на реализации ресурса и её контракте.
AutoCloseable?Нет. Сам факт реализации интерфейса гарантирует лишь наличие метода закрытия с соответствующей сигнатурой и контрактом исключений. Идемпотентность — отдельное свойство конкретной реализации; его нужно проверять по документации или обеспечивать самостоятельно в собственном классе.
close() должен быть ошибкой, а не пустой операцией?Потому что повторное закрытие может указывать на нарушение протокола использования: например, объект уже передан владельцу другого слоя или его состояние нельзя безопасно восстановить. В таком API исключение помогает обнаружить ошибку программиста, но такой выбор нужно явно документировать, поскольку он хуже сочетается с обобщённым кодом управления ресурсами.