Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java 8 - Once Stream is consumed and operated giving error, but in another case its not

I am new to Java 8 and looking to understand the difference between the two scenarios. I know that once a stream is operated and consumed then stream cant be reused again it will give an error.

Scenario-1:

List<String> title = Arrays.asList("Java8", "In", "Action");
        Stream<String> s = title.stream();
        s.forEach(System.out::println);
        s.forEach(System.out::println); // THIS WILL GIVE ERROR - streams has been already operated and closed.

When I run this, I get below error... which is fair.

Java8
In
Action
Exception in thread "main" java.lang.IllegalStateException: stream has already been operated upon or closed
    at java.util.stream.AbstractPipeline.sourceStageSpliterator(Unknown Source)
    at java.util.stream.ReferencePipeline$Head.forEach(Unknown Source)
    at com.test.Java8InAction.CH4.TraversableOnlyOnce.main(TraversableOnlyOnce.java:12)

Scenario-2:

// Filtering unique elements
List<Integer> numbers = Arrays.asList(1, 2, 1, 3, 3, 2, 4);
numbers.stream().forEach(System.out::println);
numbers.stream().filter(n -> n % 2 == 0).distinct().forEach(System.out::println);
numbers.stream().filter(n -> n % 2 == 0).forEach(System.out::println);

Here also I have operated stream and closed the terminal operation, then why I did not get any error?

like image 721
Jeff Cook Avatar asked Oct 07 '18 13:10

Jeff Cook


People also ask

Can a stream be consumed more than once?

A stream should be operated on (invoking an intermediate or terminal stream operation) only once. This rules out, for example, "forked" streams, where the same source feeds two or more pipelines, or multiple traversals of the same stream.

What happens if you apply a terminal operation to a stream twice?

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. Whenever a terminal operation is called on a Stream object, the instance gets consumed and closed.

How many times can a Java stream be consumed?

No. Java streams, once consumed, can not be reused by default. As Java docs say clearly, “A stream should be operated on (invoking an intermediate or terminal stream operation) only once.

Why streams in Java 8 are lazy?

Streams are lazy because intermediate operations are not evaluated until terminal operation is invoked. Each intermediate operation creates a new stream, stores the provided operation/function and return the new stream. The pipeline accumulates these newly created streams.


2 Answers

Because a stream can be consumed only once. if you want to use multiple time use Supplier for this.

Supplier<Stream<String>> streamSupplier = ()-> Stream.of("Java8", "In", "Action");

then use get to create a new stream.

streamSupplier.get().forEach(System.out::println);

but in second scenario you create a new stream every time.

like image 77
Hadi J Avatar answered Oct 25 '22 07:10

Hadi J


.stream() creates a new instance of a Stream despite the fact it's called on the same collection

like image 27
star67 Avatar answered Oct 25 '22 07:10

star67