Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is a Java 8 Stream considered to be consumed?

My understanding was that a Java 8 Stream is considered to be consumed once a terminal operation, such as forEach() or count(), is performed.

However, the test case multipleFilters_separate below throws an IllegalStateException even though filter is a lazy intermediate operation, just called as two statements. And yet, I can chain the two filter operations into a single statement and it works.

@Test(expected=IllegalStateException.class)
public void multipleFilters_separate() {
    Stream<Double> ints = Stream.of(1.1, 2.2, 3.3);
    ints.filter(d -> d > 1.3);
    ints.filter(d -> d > 2.3).forEach(System.out::println);
}

@Test
public void multipleFilters_piped() {
    Stream<Double> ints = Stream.of(1.1, 2.2, 3.3);
    ints.filter(d -> d > 1.3)
        .filter(d -> d > 2.3)
        .forEach(System.out::println);
}

From this, I'm assuming a Stream is considered to be consumed after the first statement that uses it whether that statement calls a terminal operation or not. Does that sound right?

like image 740
craigcaulfield Avatar asked Aug 13 '17 07:08

craigcaulfield


People also ask

Are Java streams consumable?

Java Streams are consumable i.e; to traverse the stream, it needs to be created every time. They are non-consumable i.e; can be traversable multiple times without creating it again. Java streams support both sequential and parallel processing.

Can you reuse Java 8 stream?

Java 8 streams cannot be reused.

Can Java stream be reused and visited many times?

So the simple answer is : NO, we cannot reuse the streams or traverse the streams multiple times. Any attempt to do so will result in error : Stream has already been operated on or closed.


1 Answers

A Stream is considered consumed once a terminal operation is executed. However, even multiple intermediate operations are not supposed to be executed for the same Stream instance, as stated in the Stream javadoc:

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. A stream implementation may throw IllegalStateException if it detects that the stream is being reused. However, since some stream operations may return their receiver rather than a new stream object, it may not be possible to detect reuse in all cases.

In case of intermediate stream operations, you should call the next operation on the Stream returned by the previous operation:

public void multipleFilters_separate() {
    Stream<Double> ints = Stream.of(1.1, 2.2, 3.3);
    ints = ints.filter(d -> d > 1.3);
    ints.filter(d -> d > 2.3).forEach(System.out::println);
}
like image 78
Eran Avatar answered Oct 17 '22 10:10

Eran