Reputation: 93
The below code is not printing any values. None of the System.out.println() statements are getting printed. I assumed peek deals with modifying data. Surprisingly the logic inside the peek() is not even getting executed. If I collect the stream using Collectors I see the desired behavior.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class HelloWorld {
public static void main(String[] args) {
List<String> input = new ArrayList<>(Arrays.asList("hello", "bye", "vacation"));
List<String> output = new ArrayList<>();
input.stream().peek(x -> {
System.out.println(x+"inside"); // print statement 1
if (x.length() > 3) {
output.add(x.toUpperCase());
}
});
output.forEach(System.out::println); // print statement 2
}
}
Upvotes: 0
Views: 1780
Reputation: 36601
You lack a terminal operator on your stream, so nothing will happen with it.
See https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html:
Intermediate operations return a new stream. They are always lazy; executing an intermediate operation such as filter() does not actually perform any filtering, but instead creates a new stream that, when traversed, contains the elements of the initial stream that match the given predicate. Traversal of the pipeline source does not begin until the terminal operation of the pipeline is executed.
The .collect
is a terminal operator which explains why it works when you replace close
with collect
.
Upvotes: 0
Reputation: 44378
There are several issues in the code:
Stream::peek
is an intermediate operation used mainly for debugging.output.add(x.toUpperCase());
is not good.output
is empty so nothing is printed out as long as the Stream is not closed (see the no. 1).All you need to understand Stream API is at the package description. Finally, you can conclude into something like:
List<String> output = input.stream() // Stream<String>
.peek(x -> System.out.println(x + " inside")) // print each value
.filter(x -> x.length() > 3) // filter Strings longer than 3 chars
.map(x -> x.toUpperCase()) // make them uppercase using map
.collect(Collectors.toList()); // to List - a terminal operation
Upvotes: 3
Reputation: 5246
When Stream#peek(Consumer)
is referenced, a new StatelessOp
object is created from the existing Stream
. However, the method from the StatelessOp
object called opWrapSink
is only called when the Stream elements are consumed. You are not consuming the elements of the Stream at any point. In the documentation the reasoning is that intermediate operations are done lazily.
Laziness-seeking. Many stream operations, such as filtering, mapping, or duplicate removal, can be implemented lazily, exposing opportunities for optimization. For example, "find the first String with three consecutive vowels" need not examine all the input strings. Stream operations are divided into intermediate (Stream-producing) operations and terminal (value- or side-effect-producing) operations. Intermediate operations are always lazy.
https://docs.oracle.com/javase/8/docs/api/java/util/stream/package-summary.html
Upvotes: 2