← 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

More forEach() Examples

1. forEach() with List

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List list = Arrays.asList("Java", "Selenium");
        list.forEach(s -> System.out.println(s));
    }
}
          

2. forEach() with Method Reference

list.forEach(System.out::println);
          

3. forEach() with Set

import java.util.*;

class Demo {
    public static void main(String[] args) {
        Set set = new HashSet<>(Arrays.asList(1, 2, 3));
        set.forEach(n -> System.out.println(n));
    }
}
          

4. forEach() with Map (BiConsumer)

import java.util.*;

class Demo {
    public static void main(String[] args) {
        Map map = Map.of(1, "A", 2, "B");
        map.forEach((k, v) -> System.out.println(k + " = " + v));
    }
}
          

5. forEach() on Stream

import java.util.*;

class Demo {
    public static void main(String[] args) {
        Arrays.asList(1, 2, 3)
              .stream()
              .forEach(n -> System.out.println(n));
    }
}
          

6. forEach() vs forEachOrdered() (Parallel Stream)

import java.util.*;

class Demo {
    public static void main(String[] args) {
        Arrays.asList(1, 2, 3, 4)
              .parallelStream()
              .forEach(System.out::println);
    }
}
          

Note: Order not guaranteed.

7. forEachOrdered() to Maintain Order

Arrays.asList(1, 2, 3, 4)
      .parallelStream()
      .forEachOrdered(System.out::println);
          

8. forEach() with Filtering (Stream Chain)

import java.util.*;

class Demo {
    public static void main(String[] args) {
        Arrays.asList(1, 2, 3, 4)
              .stream()
              .filter(n -> n % 2 == 0)
              .forEach(System.out::println);
    }
}
          

9. forEach() with Transformation

Arrays.asList("java", "api")
      .stream()
      .map(String::toUpperCase)
      .forEach(System.out::println);
          

10. forEach() with Index (Workaround)

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List list = Arrays.asList("A", "B", "C");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(i + " -> " + list.get(i));
        }
    }
}
          

Interview Note: forEach() does not provide index.

11. forEach() Modifying External Variable (Trap)

int sum = 0;
// Arrays.asList(1,2,3).forEach(n -> sum += n); // ❌ compilation error
          

Reason: Variable must be effectively final.

12. Correct Way Using AtomicInteger

import java.util.concurrent.atomic.AtomicInteger;
import java.util.*;

class Demo {
    public static void main(String[] args) {
        AtomicInteger sum = new AtomicInteger();
        Arrays.asList(1, 2, 3)
              .forEach(n -> sum.addAndGet(n));
        System.out.println(sum.get());
    }
}
          

13. forEach() vs Enhanced for Loop

// Enhanced for
for (String s : list) {
    System.out.println(s);
}

// forEach
list.forEach(System.out::println);
          

14. forEach() with Exception Handling

list.forEach(s -> {
    try {
        System.out.println(s);
    } catch (Exception e) {
        System.out.println("Error");
    }
});
          

15. ❌ Removing Elements Inside forEach() (Trap)

list.forEach(s -> {
    // list.remove(s); // ❌ ConcurrentModificationException
});
          

16. Correct Removal Using Iterator

Iterator it = list.iterator();
while (it.hasNext()) {
    if (it.next().equals("A")) {
        it.remove();
    }
}
          

17. forEach() with Custom Object

class User {
    String name;
    User(String name) { this.name = name; }
}

List users = List.of(new User("A"), new User("B"));
users.forEach(u -> System.out.println(u.name));
          

18. forEach() in Optional

import java.util.*;

class Demo {
    public static void main(String[] args) {
        Optional opt = Optional.of("Java");
        opt.forEach(System.out::println);
    }
}
          

19. forEach() as Terminal Operation

Arrays.asList(1, 2, 3)
      .stream()
      .forEach(System.out::println); // terminal
          

Rule: After forEach(), stream cannot be reused.

20. forEach() with Nested Collections

import java.util.*;

class Demo {
    public static void main(String[] args) {
        List> list =
            Arrays.asList(Arrays.asList(1,2), Arrays.asList(3,4));

        list.forEach(inner ->
            inner.forEach(System.out::println)
        );
    }
}
          

21. forEach() with Queue

import java.util.*;

class Demo {
    public static void main(String[] args) {
        Queue q = new LinkedList<>(List.of("A", "B"));
        q.forEach(System.out::println);
    }
}
          

22. forEach() with CopyOnWriteArrayList

import java.util.concurrent.*;

class Demo {
    public static void main(String[] args) {
        CopyOnWriteArrayList list =
            new CopyOnWriteArrayList<>(List.of(1,2));
        list.forEach(n -> list.add(3)); // allowed
        System.out.println(list);
    }
}
          

23. forEach() vs map() (Interview Trap)

// Wrong
list.forEach(s -> s.toUpperCase());

// Correct
list.stream().map(String::toUpperCase).forEach(System.out::println);
          

24. forEach() with Logging Use Case

logs.stream()
    .filter(l -> l.contains("ERROR"))
    .forEach(System.out::println);
          

25. Interview Summary – forEach()

collection.forEach()
stream.forEach()
map.forEach()
          

Key Points

  • Terminal operation (for streams)
  • No index support
  • Order not guaranteed in parallel streams
  • Cannot modify collection structure
  • Best with lambdas & method references

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.