2009-07-22 14 views
17

Aktualizacja: Jak zaznaczono @PaulGroke poniżej, sytuacja uległa zmianie w Java 7: teraz jest AutoCloseable. Który nie jest powiązany ze strumieniami i obsługiwany przez nowy konstrukt try-with-resources.Powinny być używane jako odpowiednik Java dla IDisposable .NET?

AutoCloseable to bezpośredni odpowiednik Java dla interfejsu .NET o numerze IDisposable.


Interfejs Closeable wprowadzono Java 1.5 jest ściśle związany ze strumieniami, a nawet ma specyfikator wyjątku dla IOException. Sugeruje to, że powinien on być używany wyłącznie do strumieni lub innych działań związanych z IO, a nie do logiki ogólnego czyszczenia.

pewnością opisu sposobu close() stałaby absolutnie żadnego sensu poza kontekst strumień/IO:

void close() throws IOException

Zamyka ten strumień i zwalnia zasoby systemowe związane wszelkie z nim.

Mam zatem zadeklarować własną interfejs, Disposable, z Dispose() sposobu na to, i użyć jej jako analogowego na IDisposable interfejsu .NET za? Czy powinienem ponownie użyć Closeable, nawet jeśli nie jest to idealne dopasowanie?

+1

@Pharap Istnieją dwa oddzielne wzory do implementacji 'IDisposable' wymienione na stronie, do której prowadzi łącze. Wdrożenie 'Object.Finalize()' jest wymagane tylko w stosunkowo rzadkim scenariuszu, w którym obiekt jest bezpośrednio odpowiedzialny za przydzielanie zasobów niezarządzanych (tj. Zasobów natywnych, które nie są pakowane w SafeHandle). Twoje stwierdzenie, że "zalecany sposób .NET do wdrożenia' IDisposable' [...] wymaga użycia 'Object.Finalize()' "nie jest całkowicie poprawny. –

Odpowiedz

11

Szczególnie, że close() rzuca wyjątek IOException, musisz napisać kod obsługi wyjątków, radziłbym napisać własny interfejs. Interfejs ten może następnie zgłaszać wszystkie sprawdzone wyjątki, które są odpowiednie do użycia, do którego interfejs ma zostać użyty.

Interfejsy mają tendencję do wyrażania intencji w umyśle czytelnika, więc posiadanie klasy implementującej zamknięty interfejs związany z IO spowoduje, że czytelnik założy, że klasa jest również oparta na IO.

Oczywiście, jeśli obiekty, które chcesz zamknąć, to związane z IO, powinieneś użyć Closeable. Ale poza tym iść do

/** Interface for objects that require cleanup post-use. Call dispose() in finally block! */ 
public interface Disposable { 
    public void dispose(); 
} 
34

Jestem pewien, że większość ludzi zdaje sobie sprawę z tego, ale ponieważ ta kwestia jest nadal jednym z najlepszych wyników podczas wyszukiwania dla „IDisposable Java” (# 2 wynik dla mnie właśnie teraz), a to wciąż nie jest tutaj wymienione ...

Rzeczy się zmieniły w Javie 7: teraz jest AutoCloseable. Która nie jest powiązana ze strumieniami i obsługiwana przez nową konstrukcję try-with-resources.

+0

Podczas gdy uważam za irytujące, że Java zajęła tak dużo czasu, aby uzyskać odpowiednik 'IDisposable', a ja uważałem brak takiej konstrukcji za znaczącą wadę w Javie, pochwalam twórców Javy za uznanie potrzeby umożliwienia obu spróbuj zablokować wyjątki i wyczyść wyrażenia, które mają być propagowane w górę stosu wywołań. Moja własna preferencja polegałaby na tym, że 'try-with-resources' zawijałby wszystkie wyjątki, które występują w bloku cleanup w' CleanupFailedException' (co wskazywałoby, jaki wyjątek - jeśli którykolwiek - wystąpił w bloku 'try', wzdłuż z listą wyjątków czyszczenia) ... – supercat

+0

... a także zapewnia środki, za pomocą których kod czyszczenia może stwierdzić, czy blok 'try' zakończył się powodzeniem, czy też nie (na przykład, jeśli wyjątek zostanie zgłoszony przez kod, który modyfikuje coś strzeżonego przez blokadę, blokada często nie powinna być ani zwolniona, ani utrzymywana w nieskończoność, ale zamiast tego powinna zostać unieważniona, aby każda trwająca lub przyszła próba zdobycia zamka spowodowała natychmiastowy "wyjątek BadLockExitException", byłaby pomocna, gdyby spróbowała - budowa źródeł mogłaby pozwolić obiektowi blokującemu automatycznie wdrożyć taką semantykę). – supercat

+1

Zgadzam się, ale powodem jest kompatybilność wsteczna, aby zezwolić [Closeable] (http://docs.oracle.com/javase/8/docs/api/java/io/Closeable.html) na rozszerzenie [AutoCloseable] (https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html). Jedną rzeczą, którą należy wziąć pod uwagę, jest to, że wyjątek jest wrzucany do ciała, a oczyszczanie również generuje wyjątek z przepełnionymi wyjątkami [getSuppressed] (http://docs.oracle.com/javase/8/docs/api/java/lang/ Throwable.html # getSuppressed--) zawiera wyjątek od [close()] (https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html#close--). –

1

Przy wdrażaniu Closeable (lub AutoClosable dla tej sprawy) w klasie jest to również możliwe, aby po prostu pominąć rzuca deklaracja:

class X implements Closeable { 
    @Override public void close() /* I don't throw */ { 

    } 
} 

Więc gdy ktoś używa wpisywanych obiektu mogą zadzwonić close() bez konieczności złapać cokolwiek:

void f() { // notice no need for throws because close() doesn't throw 
    X x = new X(); 
    try { 
     // do something 
    } finally { 
     x.close(); 
    } 
} 

jest również kompatybilny z niczego spodziewa się Closeable: jeśli obiekt ten jest przekazywany do gdzieś, że obsługuje Closeable, oni już przewidzieć wyjątek i obsłużyć go poprawnie, choć bezskutecznie w tym przypadku.

Obejmuje bibliotek jak Guava Closeables i Java 7 try-with-zasobów, jak sugeruje Paul groke:

try (X x = new X()) { 
    // do something 
} 

Jest to rzadka zastrzeżenie choć bez możliwości ponownego wprowadzenia wyjątku w dzieci-klasach raz jest on usuwany:

class Y extends X { 
            /* compile error */ 
    @Override public void close() throws IOException { 
     // Y.close clashes with X.close: overridden method does not throw IOException 
    } 
} 
Powiązane problemy