Mehrere resources mit try-with-resources verwalten

Hm. Was genau nun „brandgefährlich“ ist, hat sich mir nicht erschlossen. Aber ich finde (auch, falls du das meintest) dass einiges im Dunstkreis von streams unerfreulich vage ist:

  • Bei den meisten stream-Wrappern wird bei einem close auch der „innere“ Stream geschlossen (aber wohl nicht bei allen)
  • Bei den meisten streams ist close idempotent (aber wohl nicht bei allen)
  • Bei den meisten streams wird bei einem close erst ein flush gemacht (aber vielleicht nicht bei allen…?)
  • Nebnbei: Auch ein normaler java.util.Stream hat ein close, und bei manchen ist es nötig, das aufzurufen, aber wohl nicht bei allen…

(Da bin ich vor einer Weile drüber gestolpert, als ich für data die Möglichkeit bieten wollte, einzelne Zeilen einer CSV über einen Stream zu verarbeiten. Das blöde ist: Wenn man einen Stream in die Hand gedrückt bekommt, weiß man nie, ob man ihn schließen muss. Man könnte meinen ~„joa, dann macht man halt was, dass er bei einer terminal operation geschlossen wird“, aber so einfach ist das alles nicht…)

Tatsächlich kann aber z.B. auch das explizite Schließen eines „eingewickelten“ Streams richtig eklig sein. Ganz grob (wirklich nur sinngemäß) bei so einem Muster:

void writeSomething(OutputStream outputStream) {
    writeSomeXml(outputStream);
    writeSomeJson(outputStream);
}
void writeSomeXml(OutputStream outputStream) {
    try (XmlWriter w = new XmlWriter(outputStream)) { ... }
}
void writeSomeJson(OutputStream outputStream) {
    try (JsonWriter w = new JsonWriter(outputStream)) { ... }
}

Wenn man mehrere Sachen hintereinander in einen Stream schreiben will, kann ein automatisches Schließen lästig sein. IIRC habe ich sogar mal was mit

class NonCloseableOutputStream implements OutputStream {
    OutputStream delegate;
    void write(byte data[]) { delegate.write(data);
    void close() { /** delegate.close()? NO! */ }
}

gepfuscht, weil’s keine andere Lösung zu geben schien (gab es IIRC aber dann doch…).

EDIT: Ganz allgemein versuche ich aber immer, wenn ein InputStream oder OutputStream an eine Methode übergeben wird, klipp und klar dazuzuschreiben, ob…

/**
 * ...
 * The given stream will be closed when the operation is finished
 */

oder

/**
 * ...
 * The caller is responsible for closing the given stream
 */

Und nach Möglichkeit mache ich letzteres: Ein stream, der einmal zu ist, den kriegt man halt nicht mehr auf. (Lästig ist es dann, wenn irgendeine Library das erstens nicht macht, und zweitens die Bedingungen, unter denen etwas geschlossen wird, haarsträubend undurchsichtig sind … )