The Stream.peek method in Java’s Stream API is an invaluable utility for debugging your stream pipeline. It provides a way to inspect (or “peek at”) the elements of your stream during the processing without modifying them. This is typically used for logging or debugging purposes.
Here’s how Stream.peek works and how you can use it for debugging:
How Stream.peek Works
- The
peekmethod takes a Consumer as an argument. A Consumer is a functional interface that takes an input and performs some operation without returning any result. peekoperates on each element of the stream as it passes through, allowing you to perform side effects, such as logging the current state of each element.- It is particularly useful for observing intermediate data in a stream processing pipeline.
Syntax
Stream<T> peek(Consumer<? super T> action)
- Parameters:
action– a non-interfering action (side effect) that will be invoked on each stream element as it gets processed. - Returns: Returns a new stream identical to the original but with the
actionapplied to each element as a side effect.
Note: Since streams in Java are lazy (operations don’t execute until a terminal operation is invoked), the peek method will only execute when a terminal operation (like collect, forEach, reduce, etc.) is triggered.
Example of Using peek for Debugging
1. Logging Intermediate Elements
package org.kodejava.util.stream;
import java.util.stream.Stream;
public class PeekExample {
public static void main(String[] args) {
Stream.of("one", "two", "three", "four") // Create the stream
.filter(str -> str.length() > 3) // Filter elements with length > 3
.peek(str -> System.out.println("After filter: " + str)) // Debug filtered elements
.map(String::toUpperCase) // Map to uppercase
.peek(str -> System.out.println("After map: " + str)) // Debug mapped elements
.forEach(System.out::println); // Final terminal operation
}
}
Output:
After filter: three
After filter: four
After map: THREE
THREE
After map: FOUR
FOUR
In this example:
peekis used after thefilterandmapstages to print the elements at each point in the stream pipeline.- This allows you to understand how elements are being processed step-by-step.
2. Debugging a Processing Sequence
Suppose you have some complex logic in your stream pipeline, and you want to verify the intermediate results during processing:
package org.kodejava.util.stream;
import java.util.Arrays;
import java.util.List;
public class StreamPeekDemo {
public static void main(String[] args) {
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
List<Integer> result = numbers.stream()
.filter(num -> num % 2 == 0) // Keep only even numbers
.peek(num -> System.out.println("Filtered: " + num)) // Debug filtered numbers
.map(num -> num * num) // Square the numbers
.peek(num -> System.out.println("Mapped: " + num)) // Debug mapped (squared) numbers
.toList(); // Terminal operation (collect to list)
System.out.println("Final result: " + result);
}
}
Output:
Filtered: 2
Mapped: 4
Filtered: 4
Mapped: 16
Filtered: 6
Mapped: 36
Final result: [4, 16, 36]
3. Warnings While Using peek
- Don’t use
peekto modify state: Ideally,peekshould only be used for debugging and observing, not for state modification. If you need to modify elements, prefer usingmap. - Streams are lazy: The
peekmethod doesn’t execute until a terminal operation (e.g.,forEach,collect) is invoked. Make sure your terminal operation is actually being called. - Avoid side effects: While
peeksupports side effects like logging or inspection, avoid introducing side effects that interfere with the expected behavior of your application.
Key Points
- Use
Stream.peekfor debugging to inspect the state of elements at specific stages in a stream pipeline. - It does not modify the stream elements, making it ideal for logging or tracing intermediate results.
- Streams only execute when a terminal operation like
forEach,collect, orreduceis called. - Avoid using
peekfor critical logic; it’s best for debugging or observational purposes only.
By adding peek strategically in your stream pipeline, you can trace how your data is transformed step by step!
