Java 8 Streams peek() API

1. Introduction

The Java Stream API introduces us to a powerful alternative for processing data.

In this short tutorial, we’ll focus on peek(), an often misunderstood method.

2. Quick Example

Let’s get our hands dirty and try to use peek(). We have a stream of names, and we want to print them to the console.

Since peek() expects a Consumer<T> as its only argument, it seems like a good fit, so let’s give it a try:

Stream<String> nameStream = Stream.of("Alice", "Bob", "Chuck");
nameStream.peek(System.out::println);

However, the snippet above produces no output. To understand why, let’s do a quick refresher on aspects of the stream lifecycle.

3. Intermediate vs. Terminal Operations

Recall that streams have three parts: a data source, zero or more intermediate operations, and zero or one terminal operation.

The source provides the elements to the pipeline.

Intermediate operations get elements one-by-one and process them. All intermediate operations are lazy, and, as a result, no operations will have any effect until the pipeline starts to work.

Terminal operations mean the end of the stream lifecycle. Most importantly for our scenario, they initiate the work in the pipeline.

4. peek() Usage

The reason peek() didn’t work in our first example is that it’s an intermediate operation and we didn’t apply a terminal operation to the pipeline. Alternatively, we could have used forEach() with the same argument to get the desired behavior:

Stream<String> nameStream = Stream.of("Alice", "Bob", "Chuck");
nameStream.forEach(System.out::println);

peek()‘s Javadoc page says: “This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline“.

Let’s consider this snippet from the same Javadoc page:

Stream.of("one", "two", "three", "four")
  .filter(e -> e.length() > 3)
  .peek(e -> System.out.println("Filtered value: " + e))
  .map(String::toUpperCase)
  .peek(e -> System.out.println("Mapped value: " + e))
  .collect(Collectors.toList());

It demonstrates, how we observe the elements that passed each operation.

On top of that, peek() can be useful in another scenario: when we want to alter the inner state of an element. For example, let’s say we want to convert all user’s name to lowercase before printing them:

Stream<User> userStream = Stream.of(new User("Alice"), new User("Bob"), new User("Chuck"));
userStream.peek(u -> u.setName(u.getName().toLowerCase()))
  .forEach(System.out::println);

Alternatively, we could have used map(), but peek() is more convenient since we don’t want to replace the element.

5. Conclusion

In this short tutorial, we saw a summary of the stream lifecycle to understand how peek() works. We also saw two everyday use cases when using peek() is the most straightforward option.

And as usual, the examples are available over on GitHub.

Related posts:

Logging a Reactive Sequence
Java String Conversions
HashSet trong Java hoạt động như thế nào?
Java Program to Implement Sparse Array
Java Program to Implement Find all Back Edges in a Graph
A Guide to Java HashMap
Java Program to Construct an Expression Tree for an Infix Expression
Java Program to Compute the Area of a Triangle Using Determinants
Prevent Brute Force Authentication Attempts with Spring Security
An Example of Load Balancing with Zuul and Eureka
Java Program to Perform Left Rotation on a Binary Search Tree
ETL with Spring Cloud Data Flow
Hướng dẫn sử dụng Java String, StringBuffer và StringBuilder
Integer Constant Pool trong Java
Guide to java.util.concurrent.BlockingQueue
New Features in Java 14
Spring Boot - Service Components
Java Program to Check Whether a Weak Link i.e. Articulation Vertex Exists in a Graph
Guava CharMatcher
Error Handling for REST with Spring
Setting Up Swagger 2 with a Spring REST API
OAuth2 for a Spring REST API – Handle the Refresh Token in Angular
Netflix Archaius with Various Database Configurations
Java Program to Implement Hamiltonian Cycle Algorithm
Java equals() and hashCode() Contracts
Wiring in Spring: @Autowired, @Resource and @Inject
Một số nguyên tắc, định luật trong lập trình
Finding Max/Min of a List or Collection
Java Program to Implement Johnson’s Algorithm
Java 8 Stream findFirst() vs. findAny()
Java Program to Find MST (Minimum Spanning Tree) using Prim’s Algorithm
Jackson – JsonMappingException (No serializer found for class)