Is there any way to reuse a Stream? [duplicate]

I'm learning the new Java 8 features, and while experimenting with streams (java.util.stream.Stream) and collectors, I realized that a stream can't be used twice.

Is there any way to reuse it?


From the documentation:

A stream should be operated on (invoking an intermediate or terminal stream operation) only once.

A stream implementation may throw IllegalStateException if it detects that the stream is being reused.

So the answer is no, streams are not meant to be reused.


If you want to have the effect of reusing a stream, you might wrap the stream expression in a Supplier and call myStreamSupplier.get() whenever you want a fresh one. For example:

Supplier<Stream<String>> sup = () -> someList.stream();
List<String> nonEmptyStrings = sup.get().filter(s -> !s.isEmpty()).collect(Collectors.toList());
Set<String> uniqueStrings = sup.get().collect(Collectors.toSet());

As others have said, "no you can't".

But it's useful to remember the handy summaryStatistics() for many basic operations:

So instead of:

List<Person> personList = getPersons();

personList.stream().mapToInt(p -> p.getAge()).average().getAsDouble();
personList.stream().mapToInt(p -> p.getAge()).min().getAsInt();
personList.stream().mapToInt(p -> p.getAge()).max().getAsInt();

You can:

// Can also be DoubleSummaryStatistics from mapToDouble()

IntSummaryStatistics stats = personList.stream()
                                       .mapToInt(p-> p.getAge())
                                       .summaryStatistics();

stats.getAverage();
stats.getMin();
stats.getMax();

The whole idea of the Stream is that it's once-off. This allows you to create non-reenterable sources (for example, reading the lines from the network connection) without intermediate storage. If you, however, want to reuse the Stream content, you may dump it into the intermediate collection to get the "hard copy":

Stream<MyType> stream = // get the stream from somewhere
List<MyType> list = stream.collect(Collectors.toList()); // materialize the stream contents
list.stream().doSomething // create a new stream from the list
list.stream().doSomethingElse // create one more stream from the list

If you don't want to materialize the stream, in some cases there are ways to do several things with the same stream at once. For example, you may refer to this or this question for details.