Java - Should I Return a Stream or a Collection?

  • For most of the cases you should return Stream. It is more flexible, is designed for better performance, and can be easily turned into Collection.
  • You should return Collection when there are strong consistency requirements and you have to produce snapshot of a moving target. Then you will want to put the elements into a collection that will not change.

Recently at my work, we were talking about our old legacy code. We talked about first projects using Java 8 and Streams API.
We came to the conclusion that it has an enormous amount of that API in it. Methods return streams everywhere, and even streams of streams.

I started wondering what is the correct - also known as best practice - of returning a collection in Java, having in mind Java 8 new stream API. I found that for the most of the cases I return simple Collection, or even an Iterable. Very seldom, when I want to ensure caller what is the type of data he receives I also return Set or List.

But the question that I had in mind was: what is the idiomatic way of returning a collection of objects when a caller should not care about its internals and ordering / duplicate invariants. Making a long story short: is Stream a new and right way of returning more than 1 item?

So I asked at JVM Poland Slack Team and people gave me a link to a similar question posted on Stack Overflow: Should I return a Collection or a Stream?.

Luckily the answer was posted by Brian Goetz - co-author of Java Stream API.
He stated that for most of the cases the Stream is the preferable type to be returned for a collection of elements.

Of course, like everything it depends, but generally speaking, it should be your first choice. Why? There are a couple of reasons.

It can give you an infinite number of items. If the result might be very large producing items one by one - instead of materializing them all into one collection - is better for your heap. When a caller is filtering, aggregating & limiting the number of items, Stream already has built-in methods to do that. It’s lazy loaded. Items are given only when you actually use them, instead of a moment when you declare stream.

One thing that you have to consider using streams is that reading from them is a terminal operation. It means you can’t read the same stream twice.
That may be a problem when you want to call multiple methods on a stream, like below.

Stream<Long> lottoNumbers = lotto.numbers();
lottoNumbers.count(); // 15
lottoNums.forEach(System.out::print); // error!

In such scenarios, you can go one of two ways. First is to return a Collection. Second to collect received stream with Stream.collect(Collectors.toList()) for example.


So as creators said I encourage you to return Stream as your first and preferable choice and return other collection after a thought that will tell you it’s a better in a given scenario.

And please. Do not return stream of streams ;)