Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Re-using a stream in Java 8 [duplicate]

In using Java streams in a project, I attempted to re-use a stream as such.

I start with a collection of objects, then do some filtering.

Collection<MyClass> collection = /* form the collection */;
Stream<MyClass> myStream = collection.stream().filter(/* some filter */);

I then want to re-use this same stream multiple times. For instance, first I want to just get the first item from the stream, as such.

MyClass first = myStream.findFirst().get();

Then I do some other stuff, and later I want to use the filtered myStream again to perform an operation on each object in the stream.

myStream.forEach(/* do stuff */);

However, when I try to do this, I get this error.

java.lang.IllegalStateException: stream has already been operated upon or closed

I can solve the issue by doing one of the following:

  • Create a new stream from the original collection and filter it again
  • Collect the stream into a filtered collection, then create a stream on that

So I guess there are a few questions I have based on my findings.

  1. If you cannot re-use streams, then when would it ever be useful to return an instance of a stream for later use?
  2. Can streams be cloned so that they can be re-used without causing an IllegalStateException?
like image 718
Andrew Mairose Avatar asked Jul 29 '15 20:07

Andrew Mairose


1 Answers

If you cannot re-use streams, then when would it ever be useful to return an instance of a stream for later use?

If you have a method that returns a stream and you need that stream to do two things, just call the method two times and get two different streams.

Can streams be cloned so that they can be re-used without causing an IllegalStateException?

Lambda expressions make it easy to set up a Supplier<Stream> so you can avoid rebuilding it. It might be an overkill if all you do is one .filter, but for more complex stream setups that are too local to warrant a method, this is a good option:

Supplier<Stream<MyClass>> sup = () -> collection.stream().....;  /

first = sup.get().findFirst().get(); // do one thing
sup.get().forEach(...);  // do another thing
like image 156
Misha Avatar answered Oct 05 '22 23:10

Misha