← Back to Home

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 action)
          

Example

List list = 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:

List result =
    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.