Sollten Java 8 Stream-Instanzen immer close () sein?

12

Sprich der Javadoc :

Streams haben eine BaseStream.close () -Methode und implementieren AutoCloseable, aber fast alle Stream-Instanzen müssen nach der Verwendung nicht wirklich geschlossen werden. Im Allgemeinen müssen nur Streams geschlossen werden, deren Quelle ein E / A-Kanal ist (z. B. die von Files.lines (Path, Charset) zurückgegebenen). Die meisten Streams werden von Sammlungen, Arrays oder generierenden Funktionen unterstützt, für die keine spezielle Ressourcenverwaltung erforderlich ist. (Wenn ein Stream geschlossen werden muss, kann er in einer try-with-resources-Anweisung als Ressource deklariert werden.)

"Fast alle" und "allgemein" sind vage - wenn Sie eine Bibliothek schreiben und den Benutzern dieses Streams die Quelle Ihres Streams entziehen, müssen Sie sich auf jeden Fall die Frage stellen - "sollte ich schließen Dies?" E / A-gestützte Streams müssen geschlossen werden, da Terminaloperationen nicht aufgerufen closewerden. Daher muss ich mich immer daran erinnern, woher mein Stream stammt, oder ich muss closees immer dokumentieren .

Ich schätze, die nukleare Option wäre, keine Streams von Methoden zurückzugeben oder Stream-Parameter zu akzeptieren. Dies ist eine Ansicht, die von einigen Leuten im JDK-Team bestätigt wurde. Ich finde, dass dies in Anbetracht des praktischen Nutzens von Streams zu einschränkend ist.

Was sind Ihre bewährten Methoden zum Schließen von Streams? Ich habe online nach einer Antwort von einigen der JDK-Leute gesucht, die normalerweise in ähnlichen Community-Fragen aktiv sind, aber nichts Relevantes gefunden haben.

RuslanD
quelle
Kein Java-Entwickler, aber ich würde diese Regeln anwenden: - Wenn ein Stream als Argument übergeben wird, dokumentieren Sie, dass der Aufrufer den Stream bei Bedarf schließen muss. - Wenn der Stream von einer Funktion an Sie zurückgegeben wird, müssen Sie ihn schließen.
Bart van Ingen Schenau

Antworten:

6

Wie Sie bereits sagten, müssen Sie in Java genau wissen, wer für die Freigabe welcher Ressource verantwortlich ist, damit Sie die entsprechenden try-catch-Konstrukte, try-with-resources oder die Delegierung dieser Aufgabe vornehmen können.

Das einzige, worauf Sie sich verlassen können, wenn der GC für Sie aufräumt, ist 100% reiner Speicher.
Wenn es vielleicht einige andere Ressourcen in gemischt sein, das einzige , was man vernünftigerweise tun kann , ist einfach auf Nummer sicher.

Deduplizierer
quelle
Ist closedas also im Grunde die einzig sichere Alternative? Ich denke, die Frage ist, wie man Code nicht jedes Mal übermäßig hässlich aussehen lässt, wenn ein Stream nützlich ist.
RuslanD,
1
Ja, wenn es vielleicht nicht-Speicher - Ressourcen sein, die einzige sichere Sache zu tun ist , zu annehmen , dass es sind . Daran führt kein Weg vorbei, obwohl Java für Ressourcen ohne GC sehr ungeeignet ist.
Deduplizierer
Wenn es sich also nur um einen Stream zwischen zwei Sammlungen handelt (reiner Speicher), ist das Schließen nicht erforderlich?
Amalgovinus
@ Malgovinus richtig
Brad Cupit
5

Was "Best Practices" anbelangt, ist es meiner Meinung nach eine gute Idee, eine Namenskonvention für Methoden zu verwenden, die "Ressourcenströme" zurückgeben.

Wenn ein Stream bearbeitet werden muss close(), rufen Sie die Factory-Methode open()oder auf openStream(). Rufen Sie Methoden auf, die kurzlebige Datenströme stream()gemäß der vom SDK festgelegten Konvention erstellen. Setzen Sie immer javadoc auf die Methode, um den Client darauf hinzuweisen, dass er es muss close().

public interface StreamingServer<RECORD> {
    /** 
     * Return a memory-efficient record stream from {@code source}.
     * Clients <em>must</em> call {@link Stream#close} to dispose the
     * stream.
     */
    Stream<RECORD> openStream(URI source) throws IOException;
}

Ich wünschte, die SDK-Autoren hätten sich nicht entschieden, AutoCloseabledie Basis-Stream-Klasse zu aktivieren. Ein eindeutiger ResourceStreamUntertyp, der sich trivial umsetzt AutoCloseable, hätte die unterschiedlichen Verträge deutlich gemacht. Dann konnten Sie ein Streamnicht benötigtes nicht schließen und ResourceStreamin statischen Analysewerkzeugen möglicherweise falsch verwaltetes feststellen .

Abhängig von den Anforderungen Ihrer Codebasis (und Ihrer Fähigkeit, Konventionen bei der Codeüberprüfung durchzusetzen) können Sie selbst eine engmaschige Stream-Unterklasse einrichten. Oder wenn Sie Ihre eigenen statischen Analysetools erstellen möchten, eine Methodenanmerkung, mit der verwaltete Ressourcen direkt gekennzeichnet werden.

@RequiresClose
Stream<RECORD> openStream(URI source) throws IOException { ... }
Jason Trump
quelle