implementiert Closeable oder implementiert AutoCloseable

127

Ich bin gerade dabei, Java zu lernen und kann keine gute Erklärung für das implements Closeableund das findenimplements AutoCloseable Schnittstellen finden.

Bei der Implementierung von interface Closeablehat meine Eclipse-IDE eine Methode erstellt public void close() throws IOException.

Ich kann den Stream pw.close();ohne die Schnittstelle schließen. Aber ich kann nicht verstehen, wie ich das implementieren kannclose() Methode über die Schnittstelle . Und was ist der Zweck dieser Schnittstelle?

Außerdem würde ich gerne wissen: Wie kann ich überprüfen, ob IOstream wirklich geschlossen wurde?

Ich habe den folgenden Basiscode verwendet

import java.io.*;

public class IOtest implements AutoCloseable {

public static void main(String[] args) throws IOException  {

    File file = new File("C:\\test.txt");
    PrintWriter pw = new PrintWriter(file);

    System.out.println("file has been created");

    pw.println("file has been created");

}

@Override
public void close() throws IOException {


}
Malas
quelle
2
Ich denke, alles ist bereits gesagt, aber vielleicht interessiert Sie der folgende Artikel über das Anprobieren von Ressourcen: docs.oracle.com/javase/tutorial/essential/exceptions/… . Dies kann auch hilfreich sein, um die gegebenen Antworten zu verstehen.
Crusam

Antworten:

40

Es scheint mir, dass Sie mit Schnittstellen nicht sehr vertraut sind. In dem Code, den Sie gepostet haben, müssen Sie nicht implementierenAutoCloseable .

Sie müssen (oder sollten) nur implementieren Closeableoder AutoCloseablewenn Sie im Begriff sind, Ihre eigenen zu implementierenPrintWriter , die Dateien oder andere Ressourcen verarbeiten, die geschlossen werden müssen.

In Ihrer Implementierung reicht es aus, aufzurufen pw.close(). Sie sollten dies in einem finally-Block tun:

PrintWriter pw = null;
try {
   File file = new File("C:\\test.txt");
   pw = new PrintWriter(file);
} catch (IOException e) {
   System.out.println("bad things happen");
} finally {
   if (pw != null) {
      try {
         pw.close();
      } catch (IOException e) {
      }
   }
}

Der obige Code bezieht sich auf Java 6. In Java 7 kann dies eleganter erfolgen (siehe diese Antwort ).

Kai
quelle
3
Warum nur mit einem PrintWriter? Insbesondere AutoClosableObjekte können unter viel mehr Umständen als nur PrintWriter...
glglgl
3
Du liegst absolut richtig. Die Frage war ungefähr PrintWriterso, dass ich sie genauer erwähnte.
Kai
7
Warum die Situation für Java 6 im Kontext von beschreiben AutoCloseable? Zeigen Sie lieber try-with-resourcesstattdessen ...
1
191

AutoCloseable(eingeführt in Java 7) ermöglicht die Verwendung des Try-with-Resources- Idioms:

public class MyResource implements AutoCloseable {

    public void close() throws Exception {
        System.out.println("Closing!");
    }

}

Jetzt können Sie sagen:

try (MyResource res = new MyResource()) {
    // use resource here
}

und JVM ruft close()automatisch für Sie an.

Closeable ist eine ältere Schnittstelle. Aus irgendeinem GrundUm die Abwärtskompatibilität zu gewährleisten, haben Sprachdesigner beschlossen, eine separate zu erstellen. Dies ermöglicht nicht nur die Verwendung aller CloseableKlassen (wie das Auslösen von Streams IOException) beim Ausprobieren von Ressourcen, sondern auch das Auslösen allgemeinerer geprüfter Ausnahmen von close().

Im Zweifelsfall sind AutoCloseableBenutzer Ihrer Klasse dankbar.

Tomasz Nurkiewicz
quelle
107
Der Grund ist einfach: Closeable.close()Würfe IOException. Viele close()Methoden , die von Try-mit-Ressourcen werfen andere geprüfte Ausnahmen profitieren könnten (zB java.sql.Connection.close()so AutoCloseable.close()wirft Exceptionden bestehenden ändern. CloseableVertrag alle bestehenden Anwendungen brechen würde / Bibliothek auf dem Vertrag zu verlassen , dass close()nur wirft IOExceptionund nicht alle (markiert) Ausnahmen.
Mark Rotteveel
4
@ MarkRotteveel: +1, danke. Ich habe meine Antwort korrigiert, um Ihre Vorschläge und Kommentare widerzuspiegeln.
Tomasz Nurkiewicz
9
Und außerdem: Closeable.close()muss idempotent sein. AutoCloseable.close()ist nicht, obwohl es immer noch dringend empfohlen wird.
Lukas Eder
2
Verwenden Sie auch nicht die Standardeinstellung public void close( ) throws Exception - verwenden Sie eine spezifischere Ausnahme, wenn Sie können (z. B. IOException)
gerardw
3
Closeablegarantiert keine Idempotenz. Es erfordert Idempotenz bei der Implementierung der close()Methode durch einen Benutzer . Und ob dies IOExceptionspezifischer / angemessener ist, hängt vom Anwendungsfall ab.
xdhmoore
70

Closeableerweitert AutoCloseableund ist speziell für E / A-Streams vorgesehen: Es löst IOException anstelle von Exception aus und ist idempotent, während AutoCloseable diese Garantie nicht bietet.

Dies alles wird im Javadoc beider Schnittstellen erklärt.

Durch die Implementierung von AutoCloseable (oder Closeable) kann eine Klasse als Ressource des in Java 7 eingeführten Try-with-Resources-Konstrukts verwendet werden, mit dem solche Ressourcen am Ende eines Blocks automatisch geschlossen werden können, ohne dass ein abschließender Block hinzugefügt werden muss, der geschlossen wird die Ressource explizit.

Ihre Klasse stellt keine verschließbare Ressource dar, und es macht absolut keinen Sinn, diese Schnittstelle zu implementieren: Ein IOTest kann nicht geschlossen werden. Es sollte nicht einmal möglich sein, es zu instanziieren, da es keine Instanzmethode gibt. Denken Sie daran, dass die Implementierung einer Schnittstelle bedeutet, dass es eine gibt zwischen der Klasse und der Schnittstelle eine Beziehung besteht. Sie haben hier keine solche Beziehung.

JB Nizet
quelle
5
Implementieren Sie einfach Closable für Streams-bezogene Klassen und AutoClosable für andere, für die die Funktion zum automatischen Schließen erforderlich ist.
Lospejos
7

Hier ist das kleine Beispiel

public class TryWithResource {

    public static void main(String[] args) {
        try (TestMe r = new TestMe()) {
            r.generalTest();
        } catch(Exception e) {
            System.out.println("From Exception Block");
        } finally {
            System.out.println("From Final Block");
        }
    }
}



public class TestMe implements AutoCloseable {

    @Override
    public void close() throws Exception {
        System.out.println(" From Close -  AutoCloseable  ");
    }

    public void generalTest() {
        System.out.println(" GeneralTest ");
    }
}

Hier ist die Ausgabe:

GeneralTest 
From Close -  AutoCloseable  
From Final Block
Lova Chittumuri
quelle
Es ist besser, die Ausgabe auch zu schreiben, damit für einen so kurzen Code kein Testprojekt erforderlich ist.
Raxetul
Müssen wir bei der Methode close () die Ressource nicht explizit schließen? Es gibt vielleicht nur eine Druckanweisung.
Shailesh Waghmare
@ShaileshWaghmare ja genau. aber zu Testzwecken habe ich im Code-Snip erwähnt.
Lova Chittumuri
@LovaChittumuri Also wird es wie this.close()oder etwas im Code sein?, Weil es automatisch aufgerufen wird (nur um sicher zu sein)
Shailesh Waghmare
@shailesh Waghmare Möchtest du mich testen?
Lova Chittumuri
6

Die try-with-resourcesAussage.

Dies try-with-resources statementist eine tryAnweisung, die eine oder mehrere Ressourcen deklariert. A resourceist ein Objekt, das geschlossen werden muss, nachdem das Programm damit beendet wurde. Das try-with-resources statementstellt sicher , dass jede Ressource an dem Ende der Anweisung geschlossen ist. Jedes implementierte Objekt, java.lang.AutoCloseableeinschließlich aller implementierten Objekte java.io.Closeable, kann als Ressource verwendet werden.

Das folgende Beispiel liest die erste Zeile aus einer Datei. Es verwendet eine Instanz von BufferedReader, um Daten aus der Datei zu lesen. BufferedReaderist eine Ressource, die geschlossen werden muss, nachdem das Programm damit beendet wurde:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

In diesem Beispiel ist die in der Anweisung try-with-resources deklarierte Ressource ein BufferedReader. Die Deklarationsanweisung wird unmittelbar nach dem Schlüsselwort try in Klammern angezeigt. Die Klasse BufferedReaderimplementiert in Java SE 7 und höher die Schnittstelle java.lang.AutoCloseable. Da die BufferedReaderInstanz in einer try-with-resource-Anweisung deklariert ist, wird sie geschlossen, unabhängig davon, ob die try-Anweisung normal oder abrupt ausgeführt wird (aufgrund der Methode BufferedReader.readLine, die eine auslöst IOException).

Vor Java SE 7 können Sie mithilfe eines finallyBlocks sicherstellen, dass eine Ressource geschlossen wird, unabhängig davon, ob die try-Anweisung normal oder abrupt ausgeführt wird. Im folgenden Beispiel wird ein finallyBlock anstelle einer try-with-resourcesAnweisung verwendet:

static String readFirstLineFromFileWithFinallyBlock(String path)
                                                     throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }

}

Bitte beachten Sie die Dokumente .

inder
quelle
6

Kürzlich habe ich ein Java SE 8 Programmer Guide ii Book gelesen.

Ich habe etwas über den Unterschied zwischen AutoCloseablevs gefunden Closeable.

Die AutoCloseableSchnittstelle wurde in Java 7 eingeführt. Davor gab es eine andere Schnittstelle namens Closeable. Es war ähnlich wie das, was die Sprachdesigner wollten, mit den folgenden Ausnahmen:

  • Closeableschränkt die Art der ausgelösten Ausnahme ein IOException.
  • Closeable erfordert, dass Implementierungen idempotent sind.

Die Sprachdesigner legen Wert auf Abwärtskompatibilität. Da das Ändern der vorhandenen Schnittstelle unerwünscht war, wurde eine neue aufgerufen AutoCloseable. Diese neue Schnittstelle ist weniger streng als Closeable. Da es Closeabledie Anforderungen für erfüllt AutoCloseable, begann es mit der Implementierung, AutoCloseableals letzteres eingeführt wurde.

Arvind Katte
quelle
1
Anstatt zu sagen, dass "Diese neue Schnittstelle weniger streng ist als Closeable", würde ich vorschlagen, dass "Diese neue Schnittstelle kann in allgemeineren Kontexten verwendet werden, in denen die beim Schließen ausgelöste Ausnahme nicht unbedingt eine IOException ist". Im Java-Universum hat "weniger streng" eine negative Stimmung.
Brunnenkopf