Frage Müssen Sie Streams schließen?


Diese Frage besteht aus zwei Teilen:

Was ist der Unterschied zwischen InputStream i1 = new InputStream() und new InputStream()?
und
Lohnt es sich, alle lokalen Variablen zu erstellen, nur um sie zu schließen?

Ich kenne die einfachen Antworten mit der ersten Möglichkeit, die Variable beizubehalten, weiterhin die Variable zu verwenden und sogar den Eingabestrom wie einen guten Programmierer zu schließen. Die Sekunde, die Sie seine Referenz verloren haben, aber es sieht prägnanter aus. Gibt es einen Unterschied in der Erinnerung zwischen den beiden? Wie wäre es mit Geschwindigkeitsunterschied (in der Zerstörung)?

Nun zu den Beispielen, die meine Gedanken angespornt haben. Zuerst verwenden wir `` new Object () `, ohne es zu verwerfen.

 public void getLongStrings() throws IOException {
        try {
            foo = FileCopyUtils.copyToString(new InputStreamReader(aBook.getInputStream()));
            bar = FileCopyUtils.copyToString(new InputStreamReader(aNovel.getInputStream()));
        }
        catch (IOException ioe) {
            //do something appropriate here;
        }
    }

Jetzt für die ausführlichere Methode

public void getLongStrings() throws IOException {
        InputStream i1 = null;
        InputStream i2 = null;
        InputStreamReader isr1 = null;
        InputStreamReader isr2 = null;
        try {
            i1 = aBook.getInputStream();
            i2 = aNovel.getInputStream();
            isr1 = new InputStreamReader(i1);
            isr2 = new InputStreamReader(i2);
            foo = FileCopyUtils.copyToString(isr1);
            bar = FileCopyUtils.copyToString(isr2);
        }
        catch (IOException ioe) {
            //do something appropriate here
        } finally {
            if (i1 != null) i1.close();
            if (i2 != null) i2.close();
            if (isr1 != null) isr1.close();
            if (isr2 != null) isr2.close();
        }
    }

Ist das erste oder zweite besser? Ist einer schneller über den anderen? Ist es schlau, alle meine Streams zu schließen, obwohl es nicht hübsch aussieht?

Vielen Dank für Ihre Einsichten (oder Bearbeitungen).


5
2018-05-22 22:14


Ursprung


Antworten:


Die Sekunde, die Sie seine Referenz verloren haben, aber es sieht prägnanter aus.

Ja, es ist prägnanter. Du machst weniger mit dem Objekt - Wichtig ist, dass du die Dinge nicht tust sollte tun. Wenn Sie eine Verknüpfung verwenden, wird häufig weniger Code erzeugt. Wenn Sie jedoch Dateigriffe offen lassen, während der Finalizer die Dinge schließt, werden Sie feststellen, dass Sie Ausnahmen erhalten, die schwer zuverlässig reproduziert werden können.

Gibt es einen Unterschied in der Erinnerung zwischen den beiden?

Vielleicht, aber das ist nicht relevant. Die wichtige Ressource hier ist nicht der Speicher, sondern das Dateihandle.

Wie wäre es mit Geschwindigkeitsunterschied (in der Zerstörung)?

Auch hier ist es wahrscheinlich irrelevant. Korrektheit ist viel wichtiger.

(Beachten Sie, dass Ihr aktueller zweiter Code immer noch nicht absolut zuverlässig ist - wenn einer der frühen close() Anrufe werfen eine Ausnahme, Sie werden den Rest nicht schließen.)

Wenn Sie Java 7 verwenden, sollten Sie sich die try-with-resources-Anweisung, was alles viel einfacher macht.

EDIT: Wie in JB Nizets Antwort erwähnt, den Code, den Sie verwenden kann Schließen Sie bereits den zugrunde liegenden Stream - es hängt davon ab, was FileCopyUtils ist. Wenn es die Spring-Klasse ist, geht es dir gut. Wenn es etwas anderes ist, kannst du es nicht sein. Sie sollten die Dokumentation lesen. Der allgemeine Grundsatz ist wie oben: Sie sollten sicherstellen, dass etwas schließt die Ströme. Nimm das nicht einfach deswegen an in diesem Fall Sie müssen die Dinge nicht explizit schließen, das gilt im allgemeinen Fall.

Beachten Sie, dass Guaveist es InputSupplier und OutputSupplier Schnittstellen sind hier nützlich - es ermöglicht Ihnen, die Lieferanten mit der Gewissheit zu umgehen, dass die Ein- / Ausgabe nicht geöffnet wurde noch... was bedeutet, dass anderer Code das Öffnen / Kopieren / Schließen (oder was immer benötigt wird) ausführen und alles für Sie erledigen kann ... Sie verwenden keine Objekte in Ihrem Code, die könnte geschlossen.


7
2018-05-22 22:18



Angenommen, dies ist Spring's FileCopyUtils, sein Javadoc sagt:

Alle Kopiermethoden verwenden eine Blockgröße von 4096 Byte. Schließen Sie alle betroffenen Streams, wenn Sie fertig sind.

(Hervorhebung von mir)

In diesem Fall ist Ihr Einstieg also völlig in Ordnung: Spring übernimmt das Schließen des Readers, und das Schließen eines Readers schließt den eingepackten Stream.

Wenn dies nicht der Fall wäre, müssten Sie den Reader schließen, vorzugsweise mit Java 7 Versuche es mit Ressourcen.

Beachten Sie, dass Ihr zweites Beispiel den Stream schließt, aber nicht muss: Wenn Sie den Reader schließen, wird er automatisch geschlossen. Wenn der erste Leser nicht geschlossen werden kann und eine IOException auslöst, wird der zweite nicht korrekt geschlossen. Ein weiterer guter Grund zu verwenden Versuche es mit Ressourcenwas garantiert alles schließt.


4
2018-05-22 22:22



Angenommen FileCopyUtils.copyToString()  nicht Schließen Sie den bereitgestellten Stream, dann ist der zweite Ansatz besser.

close() muss aufgerufen werden, um alle mit dem Stream verbundenen Ressourcen freizugeben. Es geht also nicht um Code-Schönheit oder Leistung, sondern um Korrektheit.

Der zweite Ansatz hat einen Fehler, wenn einer der close Aufrufe wirft eine Ausnahme alle verbleibenden close() Anrufe werden nicht aufgerufen.


1
2018-05-22 22:18