Reputation: 605
List<String> list = new ArrayList<>();
list.add("Apple");
list.add("Cherry");
list.add("Peach");
List<String> collect = list.stream()
.peek(x -> System.out.println(x))
.filter(x -> x.length()>4)
.peek(x -> System.out.println(x))
.collect(Collectors.toList());
This will print:
Apple
Apple
Cherry
Cherry
Peach
Peach
So my conclusion is :
The 1st input of the stream will be processed till the end of the stream. Only then the 2nd input of the stream will be processed and again till the end of the stream.
That is totally different to normal method calls. Normally you would expect ALL inputs will be processed at one method call . If you call peek() I expected I will see
Apple
Cherry
Peach
but that is not the case.
So implementation of stream() would be it has a for loop inside and successively calls the following chain of methods with only a single input.
Upvotes: 3
Views: 1501
Reputation: 1015
I'll write another example here based on the question:
var list = List.of("Apple", "Cherry", "Peach");
var outputList = list.stream()
.peek(x -> System.out.println(x))
.filter(x -> x.length()>5)
.peek(x -> System.out.println(x))
.collect(Collectors.toList());
System.out.println("\n"+outputList);
this will print
Apple
Cherry
Cherry
Peach
[Cherry]
You get this because streams define a pipeline made of subsequent intermediate ops (in this case peek, filter and peek) and a final terminal op (in this case collect); when executing the terminal operation, every object in the source will be passed through the pipeline, one after another.
In this case for example you will have
"Apple" => peek(print "Apple") => filter(is "Apple" longer than 5 chars) ? NO, stop
"Cherry" => peek(print "Cherry") => filter(is "Cherry" longer than 5 chars) ? YES, continue => peek(print "Cherry") => collect(add to the output list)
"Peach" => peek(print "Peach") => filter(is "Peach" longer than 5 chars) ? NO, stop
Upvotes: 0
Reputation: 308001
Streams are built specifically to be lazily evaluated. In other words: streams try to do as few operations necessary to get to the desired result of the terminal operation (and if you don't do any terminal operations, then a stream will usually not do anything at all).
This is explicitly documented in the JavaDoc of Stream
:
Streams are lazy; computation on the source data is only performed when the terminal operation is initiated, and source elements are consumed only as needed.
Terminal operations are those that contain the text "This is a terminal operation".
Upvotes: 3
Reputation: 7220
What you are seeing is the described manner of peek
. See (emphasis mine):
Returns a stream consisting of the elements of this stream, additionally performing the provided action on each element as elements are consumed from the resulting stream.
So the peek action (or actions in your case), that you have registered will be performed when the elements are consumed.
Upvotes: 3