Java 8 forEach()
In this article, we will understand forEach()
loop added in java 8 to iterate over Collections such as a list, set or map or over java streams with example programs.
Java forEach() syntax
forEach()
is a method introduced in java 8 in java.lang.Iterable interface and can be used to iterate over a collection.
forEach()
is a default interface method which takes a java.util.function.Consumer
as argument.
Syntax of forEach()
method is given below
void forEach(Consumer<? super T> action) { }
Java docs for this method state,
Performs the given action for each element of the Iterable until all elements have been processed or the action throws an exception.
Using forEach()
forEach()
accepts an argument of type Consumer
. It is a functional interface and hence, contains a single method accept()
, which takes a single argument and returns no value.
Signature of accept()
method is
void accept(T t);
forEach()
method is invoked on a collection and is invoked automatically for each element of the collection.
Thus, it can be said that for every element, accept()
method of Consumer
interface is invoked with a collection element as argument value.
We need to define implementation of accept()
method as per our requirement.
There are 3 ways to implement accept()
method.
1. Implement Consumer interface in a class
Create a class implementing Consumer interface and hence, its accept()
method as shown below.
public class ConsumerImpl implements Consumer<String> { @Override public void accept(String s) { System.out.println(s); } }
Then, supply the object of this class to forEach()
as below
list.forEach(new ConsumerImpl());
2. Anonymous Consumer Implementation
Instead of creating a separate class for implementing Consumer
interface, define implementation of accept()
method inline as an anonymous inner class as shown below
list.forEach(new Consumer<String>(){ public void accept(String t) { System.out.println(t); } });
Type of Consumer and the type of argument of
accept()
method must be same, which is, String in above example.3. As a Lambda expression
Since Consumer
is a Functional interface, its accept()
method can be implemented as a Lambda expression as shown below
list.forEach((t) -> { System.out.println(t); });
In all examples of forEach()
, we will be using lambda expression, since it makes the code concise and clean. Also, this is the most widely implemented usage of forEach()
.
Java forEach() over list
A list can be iterated using forEach()
as shown in the example below.
// define a list of integers List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // iterate with forEach numbers.forEach(num -> { System.out.println(num); });
Java forEach() over ArrayList
More often, we need to iterate over an arraylist of custom or user defined objects.
With forEach()
, this can be done as in below example
class Employee { private int id; private String name; public Employee(int id, String name) { this.id = id; this.name = name; } // getter and setter methods } public class ArrayListIterator { public static void main(String ... a) { // create a list List<Employee> emp = new ArrayList<>(); // create employee objects Employee one = new Employee(1, "A"); Employee two = new Employee(2, "B"); // add objects to list emp.add(one); emp.add(two); // iterate list of objects with forEach emp.forEach(e -> { System.out.println("Employee name: " + e.getName()); }); }
Here, we have an arraylist of objects of custom class, Employee
, which is iterated using a forEach()
loop.
Java forEach() stream
Java 8 streams can also be iterated using forEach()
method. Example program is given below.
// define a list of integers List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // iterate over a stream numbers.stream().forEach( num -> System.out.println(num) );
Java forEach() over Map
forEach()
method can be used to loop over a Map as shown below. java.util.Map
interface defines a different forEach()
method which takes a BiConsumer
as argument.
java.util.function.BiConsumer
is a Functional interface with a single method accept()
that takes two arguments as shown below.
void accept(T t, U u);
When forEach()
is invoked on a map, it internally invokes accept()
method with key and value of current map element passed as arguments. Example,
Map<Integer, String> map = new HashMap<>(); map.put(1, "A"); map.put(2, "B"); map.put(3, "C"); map.forEach((k,v) -> { System.out.println("Key: " + k + ", Value: " + v); });
This prints
Key: 1, Value: A
Key: 2, Value: B
Key: 3, Value: C
Java forEach() over array
To use forEach()
over a java array, we need to get a stream over an array using Arrays.stream()
method as shown below.
int[] nums = {1, 2, 3, 4, 5}; Arrays.stream(nums).forEach(num-> System.out.print(num));
forEach()
cannot be directly used over an array, since it is defined in Iterable interface and arrays are no way related to this interface.
Java forEach() index
Java forEach()
loop has no mechanism to access loop counter or element index directly as in traditional for loop, since you don’t need it to access elements.
But, in case, it is required to iterate a list with index, then you can initialize an integer to 0 before the loop and increment it inside the loop as shown below
// define a list of integers List<Integer> numbers = List.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); // initialize index variable int counter = 0; numbers.forEach( num -> { System.out.println(num); counter++; });
forEach() vs for-each
for-each
, also known as enhanced for loop is compared with forEach()
but both of these have differences. Following are the important differences summarized below.
1. forEach()
is a method while for-each
is a loop.
2. forEach()
is introduced in java 1.8 while for-each
loop was added in java 1.5.
3. You can supply lambda expresssion to forEach()
but for-each
loop doesn’t support lambda expressions.
4. Lambda expression used in forEach()
loop cannot use non-final variables. Thus, below code is not allowed
int sum = 0; list.forEach( x -> { // error: sum is not final sum += x; });
While it is allowed in for-each
loop.
5. You cannot use break statement in a lambda expression given in forEach()
while it can be used in a for-each loop.
Conclusion
In conclusion, this article delved into the versatility of the Java 8 forEach()
loop for iterating through various data structures like lists, maps, streams, and arrays.
Beginning with an overview of the forEach()
syntax, it explored its usage and benefits.
Comparison between forEach() and traditional for-each loops shed light on their differences and when to choose each approach.
By mastering forEach()
loop, Java developers can streamline their code, improve readability, and leverage the enhanced functionality offered by Java 8.
Hope the article was useful.