63

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(); 
7
  • 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.) Commented Aug 1, 2016 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 statement. Commented Aug 1, 2016 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 Commented Aug 1, 2016 at 12:00
  • 5
    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. Commented Jul 10, 2018 at 9: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 Commented Feb 10, 2020 at 16:42

5 Answers 5

88

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 } 
Sign up to request clarification or add additional context in comments.

2 Comments

It is the other way around. If you know that stream will never hold resources, you do not close it. When stream is returned from a complex piece of code, it hard to say, what would happen with in the future, so one can skip close() only in simple cases.
I can't really argue with that though I would say its very bad design when streams hide the use of IO. It usually should be very obvious, e.g. by using a path or file arguments to create the stream. I actually never encountered streams where it wasn't obvious. I guess the reason might be, that streams are already rarely returned by public APIs because API developers often don't want the users being responsible for IO (or even handling streams in general)
12

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.

5 Comments

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 ...
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 but how would you know IF a stream needs closing? So I would say in very little cases, closing can be safely avoided (that is if you know all the implementation details of the Stream and how the data to that stream is provided). So it would be good practice to close a stream if you are done using it, that is why it is Closable in the first place.
@stryba But a large majority of streams are created from collections or other places so you know they don't need closing. Using try-with-resources for all those creates unnecessarily hard-to-read code. In a few cases you get streams backed by IO operations that need closing. In those cases you just have to check the documentation and be aware of that fact. It's not an optimal situation but the alternative is worse.
@Lii that is my point, if you created the collection you know, if you did not, you do not know.
9

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)); } 

5 Comments

I wonder why a terminal operation is not closing a Stream?
@KrzysztofTomaszewski for performance and consistency? If close operation could be invoked from different places, one could forget to do it in both.
@Basilevs - that is my point: close could be called automatically under the hood of any terminal operation invoked on a Stream. Nothing to forget at all.
@KrzysztofTomaszewski you are forgetting that terminal operation may not be invoked at all, but the stream still has to be closed.
@Basilevs - I know. But the close() method may not be invoked as well. Actually it doesn't have to be closed.
1

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 } 

Comments

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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.