Wenn ich diesen Code ausführen, die eine Menge von Dateien während einer Stream-Pipeline eröffnet:Schlussströme in der Mitte der Rohrleitungen
public static void main(String[] args) throws IOException {
Files.find(Paths.get("JAVA_DOCS_DIR/docs/api/"),
100, (path, attr) -> path.toString().endsWith(".html"))
.map(file -> runtimizeException(() -> Files.lines(file, StandardCharsets.ISO_8859_1)))
.map(Stream::count)
.forEachOrdered(System.out::println);
}
Ich erhalte eine Ausnahme:
java.nio.file.FileSystemException: /long/file/name: Too many open files
Das Problem ist, dass Stream.count
den Stream nicht schließt, wenn es durchquert wird. Aber ich sehe nicht, warum es nicht sollte, da es eine Terminaloperation ist. Dasselbe gilt für andere Terminaloperationen wie reduce
und forEach
. flatMap
schließt dagegen die Ströme, aus denen es besteht.
Die Dokumentation sagt mir, eine try-with-resouces-Anweisung zu verwenden, um Streams bei Bedarf zu schließen.
.map(s -> { long c = s.count(); s.close(); return c; })
Aber das ist laut und hässlich und könnte eine echte Unannehmlichkeit in einigen Fällen mit großen, komplexen Pipelines sein: In meinem Fall die count
Linie mit so etwas wie diesem, ich könnte ersetzen.
Also folgend meine Fragen sind:
- Warum die Ströme wurden nicht so konzipiert, dass Operationen, die Ströme in der Nähe auf sie arbeiten? Dadurch würden sie besser mit IO-Streams arbeiten.
- Was ist die beste Lösung zum Schließen von IO-Streams in Pipelines?
runtimizeException
ist eine Methode, die Ausnahme in RuntimeException
s geprüft einwickelt.
Warum benutzt du nicht einfach eine Standard-foreach-Schleife? In diesem Fall ist es besser geeignet als Streams – fge
@fge: Dies ist nur ein Beispiel. Ich bin daran interessiert, wie man das allgemein löst. – Lii