Close Java 8 Stream

I have to add that by default streams are not closed at all!

List<Integer> list = Arrays.asList(1,2,3,4,5,6,7,8,9,10);

// "--" is not printed at all:
list.stream().onClose(()->System.out.println("--")).forEach(x -> System.out.println(x));

System.out.println("with try(){}:");

// "--" is printed:
try (Stream<Integer> stream = list.stream() ) {
    stream.onClose(() -> System.out.println("--")).forEach(x -> System.out.println(x));
}

It is generally not necessary to close streams at all. You only need to close streams that use IO resources.

From the Stream documentation:

Streams have a BaseStream.close() method and implement AutoCloseable, but nearly all stream instances do not actually need to be closed after use. Generally, only streams whose source is an IO channel (such as those returned by Files.lines(Path, Charset)) will require closing. Most streams are backed by collections, arrays, or generating functions, which require no special resource management. (If a stream does require closing, it can be declared as a resource in a try-with-resources statement.)

If you need to close a stream, then best practice would be to use the try-with-resources statement:

try ( Stream<String> stream = Files.lines(path, charset) ) {
    // do something
}

Absolutely, by default you should close a stream.

A stream is a very generic API; the whole point is that it represents a stream of data without requiring the consumer of that data to understand where the data is coming from.

Closing a stream which does not need closing has no cost; failing to close a stream which needs closing may cause serious issues. How sure are you that the code you are writing, which currently consumes a stream of data which does not require closing, will never be repurposed to consume a different type of stream that does require closing?

I just finished refactoring a ton of code which used to use an in-memory database to use a SQL back-end instead. The code in question used streams a lot, and for good reason. Encapsulating a JDBC result set in a stream meant that I could (...I thought) achieve my goal quite easily. But... my new stream encapsulated a resource that required closing, whereas the old stream did not. Because the original developer (in this case me, I'm kicking myself) did not close the streams, much tedious debugging was required.