forEach()
The forEach() method is a terminal operation used to iterate over elements and perform an action on each element. It exists in both the Collection interface and the Stream API, with important behavioral differences.
This is a common interview topic, especially forEach() vs forEachOrdered() and Collection vs Stream usage.
What Is forEach()?
- Executes an action for each element
- Uses internal iteration
- Accepts a Consumer functional interface
- Returns void (terminal operation in streams)
forEach() in Collections
Method Signature
void forEach(Consumer super T> action)
Example
Listlist = List.of("Java", "Python", "C++"); list.forEach(s -> System.out.println(s));
- Iterates in encounter order (for List)
- Modifies allowed (not recommended)
forEach() in Stream API
list.stream()
.forEach(s -> System.out.println(s));
- Terminal operation
- Stream is consumed
- Cannot reuse stream afterward
forEach() vs Enhanced for-loop
| Aspect | forEach() | for-each loop |
|---|---|---|
| Style | Functional | Imperative |
| Iteration | Internal | External |
| Lambda support | ✔ Yes | ❌ No |
| Break/Continue | ❌ No | ✔ Yes |
| Parallel-friendly | ✔ Yes | ❌ No |
forEach() vs map() (Very Important)
| Method | Purpose |
|---|---|
| map() | Transform elements |
| forEach() | Perform side effects |
❌ Wrong
list.stream().forEach(x -> x * 2); // no effect
✔ Correct
list.stream()
.map(x -> x * 2)
.forEach(System.out::println);
forEach() vs forEachOrdered() (Interview Favorite)
forEach()
- Order not guaranteed in parallel streams
- Faster
list.parallelStream().forEach(System.out::println);
forEachOrdered()
- Maintains encounter order
- Slightly slower
list.parallelStream().forEachOrdered(System.out::println);
Using forEach() with Maps
Best Practice (entrySet)
map.forEach((key, value) ->
System.out.println(key + " = " + value)
);
- Clean
- Efficient
Side Effects & Caution (Interview Trap)
forEach() is intended for side effects (logging, printing).
❌ Avoid modifying shared state:
list.stream().forEach(x -> sharedList.add(x)); // risky
✔ Prefer:
Listresult = list.stream().map(x -> x * 2).toList();
Exception Handling in forEach()
- Lambdas cannot throw checked exceptions directly
- Must handle inside lambda
list.forEach(x -> {
try {
// risky operation
} catch (Exception e) {
e.printStackTrace();
}
});
Common Beginner Mistakes
- Using forEach() instead of map()
- Expecting return values
- Modifying source collection
- Assuming order in parallel streams
- Overusing forEach() for business logic
Best Practices
- Use forEach() for final actions (print, log)
- Prefer map(), filter(), collect() for transformations
- Use forEachOrdered() when order matters
- Avoid shared mutable state
- Keep lambdas simple
Interview-Ready Answers
Short Answer
forEach() performs an action on each element of a collection or stream.
Detailed Answer
In Java, forEach() is a terminal operation that accepts a Consumer and executes it for each element. In streams, it triggers execution and may not preserve order in parallel streams unless forEachOrdered() is used. It is mainly intended for side effects rather than data transformation.
Key Takeaway
forEach() is for actions, not transformations. Use it at the end of a stream pipeline, and be cautious with parallel execution and side effects.