What is difference between Collection.stream().forEach() and Collection.forEach()?
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
In Java, working with collections is an essential part of programming, greatly facilitated by the Java Stream API introduced in Java 8. This API not only made it possible to work with collections in a more functional programming style but also simplified many operations. Two commonly used methods to iterate over collections are Collection.stream().forEach() and Collection.forEach(). Although they might seem similar at first glance, they serve different purposes and have distinct characteristics.
Understanding Collection.forEach()
The forEach() method is part of the Iterable interface, and thus it is available in all Collection frameworks (like List, Set, etc.). It is intended to iterate over each element of the collection, executing a specified action. It is simple and straightforward, designed primarily for operating on each element sequentially. Here is a basic example:
In this example, forEach directly accesses the names list and applies the System.out.println operation to each element.
Understanding Collection.stream().forEach()
The stream().forEach() method, on the other hand, involves two operations. First, Collection.stream() converts the collection into a Stream. Second, forEach() is a terminal operation on the Stream that performs an action for each element of the Stream. Here’s how you might use it:
Though it looks similar to Collection.forEach(), using a Stream makes a huge difference, especially in terms of parallel execution and pipeline operations.
Key Differences
- Design Philosophy:
Collection.forEach()is inherently tied to the Iterable interface and is designed for simplicity and readability when performing operations on a collection directly. Conversely,stream().forEach()is designed for more complex data processing tasks and operates within the Stream API's context, providing capabilities like filtering, mapping, and reduction. - Concurrency Handling: One of the significant advantages of using
stream().forEach()is its ability to effortlessly transition to parallel execution usingparallelStream(). This is particularly useful when dealing with large collections where performance is a consideration. On the other hand,Collection.forEach()inherently does not support parallel execution and is always run sequentially. - Behavior Consistency: The behavior of
stream().forEach()does not guarantee that the operation will process the items in the collection in order, especially in parallel mode. This non-determinism can be critical in certain applications.Collection.forEach()generally maintains the iteration order, if any, of the collection.
Example to Illustrate Differences
Consider you need to print elements of a list and apply some operation. Here’s how the approaches differ:
If performOperation is an intensive task and the collection is large, turning the stream into a parallel stream could improve performance, a feat not achievable with Collection.forEach().
Best Practices and When to Use
- Use
Collection.forEach()when dealing with small to medium-sized collections where the operation is straightforward and the collection's iteration order should be preserved. - Opt for
stream().forEach()when dealing with more complex scenarios requiring operations like filtering, mapping, or when considering processing items in parallel.
Summary Table
| Feature | Collection.forEach() | stream().forEach() |
| Interface | Directly in Collection | Part of Stream API |
| Parallel Execution | Not Supported | Supported via parallelStream() |
| Order Guarantee | Maintains order | No guarantee in parallel mode |
| Use Case | Simple iterations where order matters | Complex data processing or large datasets |
In conclusion, both methods have their place in Java programming. The choice depends on the specific requirements of the application regarding processing logic, performance considerations, and scalability demands. Understanding these nuances allows developers to write more efficient and effective Java code.
Related reading
- What is Elastic IP in AWS and why it is useful?
- What is HTML5 File.slice method actually doing?
- What is Java Servlet?
- What is meant by Security Groups are stateful?
- What is difference between CrudRepository and JpaRepository interfaces in Spring Data JPA?
- What is difference between ImportAutoConfiguration and Import
- What is middleware in distributed systems?
- What is Remote Method Invocation (RMI)?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.