Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8: In spite of avoiding terminal operation, see "stream has already been operated upon or closed"

Tags:

java-8

The following java 8 stream doesn't have any terminal operation. Isn't the following block supposed to be lazy, since I only have intermediate operation and hasn't been operated yet by a terminal operation. I get "stream has already been operated upon or closed" when I run this block. See https://ideone.com/naR7GB

Stream<String> s = Stream.of("A", "B");
s.map(String::toUpperCase);
s.map(String::toLowerCase);

Stack Trace:

java.lang.IllegalStateException: stream has already been operated upon or closed
at java.util.stream.AbstractPipeline.<init>(AbstractPipeline.java:203)
at java.util.stream.ReferencePipeline.<init>(ReferencePipeline.java:94)
at java.util.stream.ReferencePipeline$StatelessOp.<init>(ReferencePipeline.java:618)
at java.util.stream.ReferencePipeline$3.<init>(ReferencePipeline.java:187)
at java.util.stream.ReferencePipeline.map(ReferencePipeline.java:186)
like image 401
Chinmay Avatar asked Mar 21 '18 15:03

Chinmay


1 Answers

You need to apply the second map() to the mapped instance:

s.map(String::toUpperCase).map(String::toLowerCase);

Or

Stream<String> s = Stream.of("A", "B");
Stream<String> s2 = s.map(String::toUpperCase);
Stream<String> s3 = s2.map(String::toLowerCase);

As you can only do 1 operation on the same stream instance.

But remember, you can only consume s once! So either you consume s2 or s3, you can not consume both. That's why we usually write a chained call, since it does not make sense to keep the intermediate objects.

like image 199
Robert Bräutigam Avatar answered Jan 03 '23 00:01

Robert Bräutigam