Detailed behavior of Stream API Stateful intermediate operation and short-circuit termination operation

Detailed behavior of Stream API Stateful intermediate operation and termination operation

First is the problem.

What about the console output of the code below?


//Question 1
		Stream.of(1, 2, 3, 4, 5).map(i -> {
			System.out.println(i);
			return i * 2;
		}).filter(i -> i > 3).findFirst();
//Question 2
		Stream.of(1, 2, 3, 4, 5).peek(System.out::println).map(i -> {
			return i * 2;
		}).filter(i -> i > 3).findFirst();
//Question 3
		Stream.of(1, 2, 3, 4, 5).peek(System.out::println).map(i -> {
			return i * 2;
		}).filter(i -> i > 3).sorted().findFirst();
//Question 4
		Stream.of(1, 2, 3, 4, 5).peek(System.out::println).map(i -> {
			return i * 2;
		}).filter(i -> i > 3).distinct().findFirst();

answer

//Question 1
1
2
//Question 2
1
2
//Question 3
1
2
3
4
5
//Question 4
1
2

Commentary

Question 1

Java Stream processing is divided into "generate", "intermediate operation", and "termination operation". Basically, the part where the generation creates the Stream, the method where the termination operation finally returns the result, It is OK if you think of the intermediate operation as the part that returns Stream from other Streams.

The actual processing is executed when the termination operation is executed. And basically, it executes the termination operation for each element flowing in Stream. Not all elements are mapped and then filtered. (For example, the behavior is different from writing similar code in a javascript array.)

And, FindFirst adopted as the termination operation this time is called short-circuit termination operation among the termination operations. Operations with a "short circuit" end processing even before all the elements flowing in the Stream are evaluated, provided that the conditions are met. (If the short-circuit operation satisfies the condition, the process can be completed without getting into an infinite loop even for a Stream that returns an infinite value (such as a Stream created from an iterator that hasNext always returns true).

In a for or while loop, there are many processes that break if even one condition is met and ignore the rest, but it does it automatically. It's smart.

In this case, findFirst can return the value when 2 flows, so Stream processing is interrupted up to 1 and 2.

Question 2

It is basically the same as Question 1. If you put a peek immediately after creating a Stream where 5 elements flow, it seems to be executed 5 times, Stream processing stops at 2 because the end is short-circuit termination processing.

Question 3

In some cases, the elements flowing through all Streams are evaluated even if short-circuit termination is performed. This is the case with "stateful intermediate processing" in between. In this case sorted is a stateful intermediate process. Since it is a process of sorting and getting the one that satisfies the condition first, Naturally, it is necessary to refer to all the elements logically.

By the way, whether each intermediate process is stateful is described in Official Reference. ..

Question 4

By the way, it is not always necessary to refer to all elements with a stateful intermediate operation. distinct is also a stateful intermediate operation, but this is also completed in 1 and 2. Rather, in fact, all elements are always referenced in a normal ordered Stream only when using sorted.

Summary

Digression

In the case of ParallelStream, the behavior is slightly different, It will be long, so around here.

Recommended Posts

Detailed behavior of Stream API Stateful intermediate operation and short-circuit termination operation
[Java] Stream API intermediate operation
behavior of didSet and willSet
[Java] Stream API --Stream termination processing
[Java] Stream API --Stream intermediate processing