peek() is an intermediate Stream operation that lets you observe each element as it flows through the pipeline, typically for debugging, without altering the stream's contents.
Key Points: • peek() takes a Consumer and is meant for side effects like logging, not for transforming elements. • It only executes if the stream pipeline has a terminal operation - streams are lazy, so peek() alone does nothing without a terminal call. • On sequential streams, elements pass through peek() in encounter order; on parallel streams, ordering guarantees weaken. • Using peek() to mutate shared state or drive core logic is discouraged - it's meant purely for observation. • Since Java 9, the JVM may optimize away peek() calls if there's no subsequent operation that actually needs the elements.
Example: Adding .peek(System.out::println) between filter() and collect() lets you print each element right after it passes the filter, which is handy for verifying an intermediate step while debugging a pipeline.
Code Example:
List<Integer> peekedAtNumbers = numbers.stream()
.peek(System.out::println)
.collect(Collectors.toList());Interview Tip: A concise interview answer is:
"peek() lets me observe elements as they flow through a stream pipeline, mainly for debugging with something like System.out::println, without changing the elements themselves. It only fires once a terminal operation runs, since streams are lazily evaluated, and it shouldn't be used to drive real application logic."