55

If we use Java 8 Stream like list.stream().filter(....).collect(..)..... When is it closed this stream?

Is it good practice that we close the stream us as the next example?

Stream<String> stream = list.stream();
String result = stream.limit(10).collect(Collectors.joining(""));
stream.close();
Pau
  • 13,250
  • 13
  • 60
  • 88
  • 9
    From the docs: 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.) – Jan B. Aug 01 '16 at 11:54
  • I don't think you need to close THAT "stream" ^) – injecteer Aug 01 '16 at 11:54
  • 3
    Streams in general do not need to be closed. Only some streams that access resouces such as a `DirectoryStream` need to be closed. The best way to do that is by using a [try-with-resources](https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html) statement. – Jesper Aug 01 '16 at 11:55
  • 1
    1. Since they are lazy so not get initialized, 2. they implement `AutoCloseable` and therefore opened stream gets closed when it is idle – bananas Aug 01 '16 at 12:00
  • 4
    **How is this a duplicate?** This question asks whether streams _should_ be closed, the other question asks if they are _automatically closed_ in some specific case. If you have a possibility to unilaterally close questions because of a golden badge, at least you should read them carefully first. – Malcolm Jul 10 '18 at 09:52
  • 1
    I am having a similar question and it seems that, after reading some of these responses, calling close method is a waste for many reasons. The first is that you have to put additional try-catch blocks with each close method which can be time consuming. The second is that any close method probably just terminates the resource so you can get the same effect by using mystream = null; statement. The third is that streams don't read directly from the file itself so the file isn't locked open until it is done like in some other languages so there is no need to close them. That is how I understand st – screwball1 Feb 10 '20 at 16:42
  • @Jesper A `DirectoryStream` is not a `javs.util.stream.Stream`. They're unrelated. – MC Emperor Mar 22 '20 at 14:47

4 Answers4

78

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
}
kapex
  • 27,631
  • 6
  • 104
  • 117
8

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.

Jonathan Essex
  • 201
  • 2
  • 4
5

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));
}
ZhekaKozlov
  • 32,979
  • 19
  • 111
  • 146
18446744073709551615
  • 15,352
  • 3
  • 89
  • 124
0

One of the streams that you need to close are the ones coming from org.hibernate.query.Query#getResultStream

You could use try-with-resources for that:

try (Stream<SomeEntity> resultStream = query.getResultStream()) {
    // process the stream
}
premek.v
  • 193
  • 5
  • 13