2009-07-22 5 views
17

Update: Wie @PaulGroke unten zeigt, haben sich die Dinge mit Java 7 geändert: Es gibt jetzt AutoCloseable. Das ist nicht an Streams gebunden und wird durch das neue try-with-resources Konstrukt unterstützt.Soll Closeable als Java-Entsprechung für IDisposable von .NET verwendet werden?

AutoCloseable ist das direkte Java-Äquivalent für die IDisposable-Schnittstelle von .NET.


Die Closeable Schnittstelle in Java eingeführt 1.5 ist eng an Ströme gebunden, und hat sogar eine Ausnahme-Spezifizierer für IOException. Dies deutet darauf hin, dass es nur für Streams oder andere E/A-bezogene Aktivitäten verwendet werden sollte, und nicht für allgemeine Bereinigungslogik.

Gewiß ist die Beschreibung für das close() Verfahren würde absolut keinen Sinn außerhalb eines Strom/IO Kontext:

void close() throws IOException

Schließt diesen Stream und gibt alle Systemressourcen mit ihm verbunden ist.

Soll ich also meine eigene Schnittstelle erklären, Disposable, mit einer Dispose() Methode auf, und verwenden Sie diese als eine Analog .NET IDisposable-Schnittstelle? Oder sollte ich Closeable wiederverwenden, obwohl es vielleicht nicht perfekt passt?

+1

@Pharap Es gibt zwei verschiedene Muster für die Implementierung von 'IDisposable' erwähnt auf der Seite, die Sie verknüpfen. Das Implementieren von 'Object.Finalize()' ist nur in dem relativ seltenen Szenario erforderlich, in dem Ihr Objekt direkt für das Zuordnen von nicht verwalteten Ressourcen verantwortlich ist (d. H. Systemeigene Ressourcen, die nicht mit einem SafeHandle umschlossen sind). Ihre Aussage, dass ".NETs empfohlene Methode zur Implementierung von IDisposable" [...] die Verwendung von 'Object.Finalize()' "erfordert, ist nicht ganz korrekt. –

Antwort

11

Insbesondere, da close() eine IOException auslöst, müssen Sie dann Ausnahmebehandlungscode schreiben, ich würde Ihnen raten, Ihre eigene Schnittstelle zu schreiben. Diese Schnittstelle kann dann alle überprüften Ausnahmen auslösen, die für die Verwendung geeignet sind, der Sie die Schnittstelle zuweisen möchten.

Schnittstellen neigen dazu, Absicht im Kopf des Lesers zu signalisieren. Wenn also eine Klasse eine IO-assoziierte Closeable-Schnittstelle implementiert, wird der Leser annehmen, dass die Klasse ebenfalls IO-basiert ist.

Offensichtlich, wenn die Objekte, die Sie schließen möchten sind alle IO-related, sollten Sie Closeable verwenden. Aber sonst geht für

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

Ich bin sicher, dass die meisten Leute davon wissen, aber da diese Frage ist nach wie vor unter den Top-Ergebnissen, wenn für „IDisposable Java“ (# 2 Ergebnis für mich gerade jetzt) ​​suchen, und es ist immer noch nicht hier erwähnt ...

Die Dinge haben sich mit Java 7 geändert: Es gibt jetzt AutoCloseable. Das ist nicht an Streams gebunden und wird durch das neue try-with-resources Konstrukt unterstützt.

+0

Während es mir lästig ist, dass Java so lange gebraucht hat, um das Äquivalent von "IDisposable" zu bekommen, und ich das Fehlen eines solchen Konstrukts als einen wesentlichen Fehler in Java ansah, lobe ich die Entwickler von Java für die Notwendigkeit, beides zuzulassen Try-Block-Exceptions und Cleanup-Ausdrücke, die im Call-Stack ausgegeben werden sollen. Meine eigene Präferenz wäre gewesen, 'try-with-resources' zu verwenden, um alle Ausnahmen, die im Cleanup-Block auftreten, in eine' CleanupFailedException' zu überführen (was anzeigen würde, welche Ausnahme - falls überhaupt - im 'try'-Block aufgetreten ist mit einer Liste von Bereinigungsausnahmen) ... – supercat

+0

... und auch eine Möglichkeit zur Verfügung stellt, mit der Bereinigungscode feststellen kann, ob der 'try' Block erfolgreich war oder fehlgeschlagen ist (zum Beispiel wenn eine Ausnahme durch einen Code ausgelöst wird, der modifiziert wird etwas, das durch eine Sperre geschützt wird, sollte oft weder freigegeben noch auf unbestimmte Zeit gehalten werden, sondern sollte stattdessen ungültig gemacht werden, so dass ein anhängiger oder zukünftiger Versuch, die Sperre zu erlangen, eine sofortige 'badLockExitException' auslösen würde; -resources Konstrukt könnte ein Sperrobjekt automatisch solche Semantiken implementieren lassen. – supercat

+1

Ich stimme dem zu, obwohl der Grund für die Abwärtskompatibilität darin liegt, [Closeable] (http://docs.oracle.com/javase/8/docs/api/java/io/Closeable.html) zu erweitern [AutoCloseable] (https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html). Eine Sache zu beachten ist, dass, wenn eine Ausnahme in den Körper geworfen wird und die Bereinigung auch eine Ausnahme auslöst die bubbled Ausnahmen [getSuppressed] (http://docs.oracle.com/javase/8/docs/api/java/lang/ Throwable.html # getSuppressed--) enthält die Ausnahme von [close()] (https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html#close--). –

1

Wenn Closeable Implementierung (oder AutoClosable was das betrifft) in einer Klasse möglich ist es auch, nur die Erklärung wirft auslassen:

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

    } 
} 

Also, wenn jemand eine typisierte Objekt verwenden, können sie close() aufrufen, ohne fangen an mit alles:

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

Es ist auch mit allem kompatibel erwartet ein Closeable: wenn dieses Objekt in irgendwo übergeben wird, die Closeable Griffe, sie antizipieren Sie bereits eine Ausnahme und behandeln Sie sie korrekt, wenn auch in diesem Fall vergeblich.

Dazu gehören Bibliotheken wie Guava Closeables und Java 7 Try-with-Ressourcen wie Paul Groke schlagen vor:

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

Es ist eine seltene Einschränkung allerdings: Sie die Ausnahme in den Kinderklassen nicht wieder einführen können, wenn es ist entfernt: