Должен ли Closeable использоваться как эквивалент Java для .NET IDisposable?
Обновление. Как показано в @PaulGroke ниже, все изменилось с Java 7: теперь есть AutoCloseable. Который не привязан к потокам и поддерживается новой конструкцией try-with-resources.
AutoCloseable
- это прямой эквивалент Java для интерфейса .NET IDisposable
.
Интерфейс Closeable
, введенный в Java 1.5, тесно связан с потоками и даже имеет спецификатор исключения для IOException
. Это говорит о том, что его следует использовать только для потоков или других видов деятельности, связанных с ИО, а не для логики очистки общего назначения.
Конечно, описание метода close()
не имело бы никакого смысла вне контекста stream/IO:
void close() throws IOException
Закрывает этот поток и освобождает связанные с ним системные ресурсы.
Должен ли я объявить свой собственный интерфейс Disposable
с помощью метода Dispose()
на нем и использовать его как аналог интерфейса .NET IDisposable
? Или я должен повторно использовать Closeable
, хотя это может быть не идеально подходит?
Ответы
Ответ 1
Особенно учитывая, что close() выбрасывает IOException, вам нужно написать код обработки исключений, я бы посоветовал вам написать свой собственный интерфейс. Этот интерфейс может затем выкинуть любые проверенные исключения, которые подходят для использования, для которого вы хотите поместить интерфейс.
Интерфейсы имеют тенденцию обозначать намерение в уме читателя, поэтому, имея реализацию класса, связанный с IO интерфейс Closeable заставит читателя предположить, что класс также основан на IO.
Очевидно, что если объекты, которые вы хотите закрыть, связаны с IO, вы должны использовать Closeable. Но в противном случае перейдите к
/** Interface for objects that require cleanup post-use. Call dispose() in finally block! */
public interface Disposable {
public void dispose();
}
Ответ 2
Я уверен, что большинство людей знают об этом, но поскольку этот вопрос по-прежнему остается одним из лучших результатов при поиске "IDisposable Java" (результат для меня сейчас только 2), и он все еще не упоминается здесь...
Все изменилось с Java 7: теперь есть AutoCloseable. Который не привязан к потокам и поддерживается новой конструкцией try-with-resources.
Ответ 3
При реализации Closeable
(или AutoClosable
в этом отношении) в классе также можно просто опустить объявление throws:
class X implements Closeable {
@Override public void close() /* I don't throw */ {
}
}
Поэтому, когда кто-то использует типизированный объект, он может вызывать close()
, не имея возможности поймать что-либо:
void f() { // notice no need for throws because close() doesn't throw
X x = new X();
try {
// do something
} finally {
x.close();
}
}
Он также совместим с любым ожидающим Closeable
: если этот объект передается где-то, где обрабатывается Closeable
, они уже предвидят исключение и обрабатывают его правильно, хотя и бесполезно в этом случае.
Это включает библиотеки, такие как Guava Closeables
и Java 7 try-with-resources, как предлагает Paul Groke:
try (X x = new X()) {
// do something
}
Там есть редкое предупреждение: вы не можете повторно вводить исключение в дочерних классах после его удаления:
class Y extends X {
/* compile error */
@Override public void close() throws IOException {
// Y.close clashes with X.close: overridden method does not throw IOException
}
}