59

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
  • 14,917
  • 14
  • 67
  • 94
  • 10
    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 –  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

5 Answers5

87

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
  • 28,903
  • 6
  • 107
  • 121
8

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
  • 36,558
  • 20
  • 126
  • 155
18446744073709551615
  • 16,368
  • 4
  • 94
  • 127
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
  • 217
  • 2
  • 4
  • Far too strong a statement as in most cases you _do_ know where the stream of data is coming from. Only APIs which take a stream as parameter wouldn't know. Even in the case that troubled you you _knew_ where the data was coming from ... – davidbak Mar 21 '23 at 12:54
  • No, by default you should NOT close a stream. You should only close it if you get it from a place which explicitly requires closing. _"Closing a stream which does not need closing has no cost"_ The cost is in unnecessary code which increases clutter and makes the code harder to read. – Lii Apr 28 '23 at 08:02
1

As I constantly reiterate, it depends on your use case. The corollary I use is: the context of the use case determines the code.

So, Files (as already stated), Scanners, and Sockets need to be manually closed. The rule is to close all IO-based streams.

What about Collections, Arrays, and Generators? Quoting from the Baeldung article: Should We Close a Java Stream?

Most of the time, we create Stream instances from Java collections, arrays, or generator functions. For instance, here, we're operating on a collection of String via the Stream API:

List colors = List.of("Red", "Blue", "Green") .stream()
.filter(c -> c.length() > 4) .map(String::toUpperCase)
.collect(Collectors.toList());

Sometimes, we're generating a finite or infinite sequential stream:

Random random = new Random(); random.ints().takeWhile(i -> i < 1000).forEach(System.out::println);

Additionally, we can also use array-based streams:

String[] colors = {"Red", "Blue", "Green"}; Arrays.stream(colors).map(String::toUpperCase).toArray()

When dealing with these sorts of streams, we shouldn't close them explicitly. The only valuable resource associated with these streams is memory, and Garbage Collection (GC) takes care of that automatically.

Another use case that I wasn't aware of is:

  • Streams passed to flatMap will be closed regardless of closing the Stream that contains them. From the javadocs

Returns a stream consisting of the results of replacing each element of this stream with the contents of a mapped stream produced by applying the provided mapping function to each element. Each mapped stream is closed after its contents have been placed into this stream. (If a mapped stream is null an empty stream is used, instead.)

Kudos to Mike for his post on Closing Java Streams with Autoclosable where he points this out.

So to summarize, the use case determines how and when to close a stream.

James Drinkard
  • 15,342
  • 16
  • 114
  • 137
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
  • 231
  • 4
  • 14