Sunday, May 8, 2022

Java 8 forEach() Loop Example

Java 8 has introduced a new way to loop over a List or Collection, by using the forEach() method of the new Stream class. You can iterate over any Collection like List, Set, or Map by converting them into a java.util.sttream.Stream instance and then calling the forEach() method. This method performs given operation on every element of Stream, which can be either simply printing it or doing something else. Since stream can be sequential or parallel, the behavior of if this method is not deterministic if used with a parallel stream

One more thing to remember about the forEach() method is that it's a terminal operation, which means you cannot reuse the Stream after calling this method. It will throw IllegalStateException if you try to call another method on this Stream.

Btw, you can also call forEach() method without obtaining Stream from list  like  listOfString.forEach(), because the forEach() method is also defined in Iterable interface, but obtaining Stream gives you more choices e.g. filtering, mapping or flattening etc.

In this article, you will learn how to loop over an ArrayList using the forEach() method of Java 8. It's one of the many Java 8 tutorials I am going to write this year. If you are Java developer with some years of experience, spend some time learning new features of Java 8, it's going to be one of the most sought after release in coming years.




How to use forEach() method to loop over List in Java

In this section, I will go over a couple of common scenarios every Java developer face in their day job. In the first example, we have a list of prime numbers and we want to print it using this new way of looping in Java 8:

List<Integer> listOfPrimes = Arrays.asList(2, 3, 5, 7, 11, 3, 17);
        
listOfPrimes.stream().forEach((i) -> { System.out.println(i); });

Here we are going through each element of the stream which is an Integer variable and passing it to System.out.println() for printing. Since forEach() method accepts a Consumer type, which is a functional interface and that's why we can pass a lambda expression to it.

You can even shorten it by using method reference, as shown below:

listOfPrimes.stream().forEach(System.out::println);

You can use method reference in place of the lambda expression if you are not doing anything with the parameter, except passing it to another method. For example, in our next two examples, we cannot replace lambda expression with method reference because we are modifying the element.

You can also see Java SE 8 for Really Impatient to learn more about method reference and lambda expression, one of the better books to learn Java. You can even apply other useful stream methods before calling forEach() e.g. in following code we are using filter() method to only print even numbers from the list of primes:

listOfPrimes.stream().filter(i -> i%2 == 0).forEach(System.out::println);

filter() method from Stream class expect a Predicate instance which is also a functional interface, with just one method which returns boolean type, hence you can use a lambda expression which returns boolean in place of Predicate.

Java 8 forEach() example to loop over list


Java 8 forEach example

You can write more code by following above techniques, I suggest you experiment with different stream methods to learn more.  Here is my sample program to demonstrate how to use forEach() statement to iterate over every element of a list, set or stream in Java.

import java.util.Arrays;
import java.util.List;

/**
 *  Java 8 forEach example to loop over Stream obtained from a List
 *
 * @author Javin
 */
public class forEachDemo{

    public static void main(String args[]) {

        List<Integer> listOfPrimes = Arrays.asList(2, 3, 5, 7, 11, 3, 17);

        // forEach example to print each element of list
        // in this case we are using method reference becasue
        // we are not doing anything with each element of collection
        // and just passing ito println method
        System.out.println("Printing elements of list using forEach method : ");
        listOfPrimes.stream().forEach(System.out::println);
     
     
        // let's do something to each element before printing
        // we will add comma after each element
        System.out.println("Printing elements after adding comma: ");
        listOfPrimes.stream().forEach( i -> System.out.print( i + ","));
     
     
        // you can also use forEach with parallel stream
        // order will not be guaranteed
        System.out.println("\nPrinting elements of list using 
                        parallel stream: ");
        listOfPrimes.parallelStream().forEach( i-> System.out.println(i*2));  
     
    }

}

Output :
run:
Printing elements of list using forEach method:
2
3
5
7
11
3
17
Printing elements after adding comma:
2,3,5,7,11,3,17,
Printing elements of list using parallel stream:
22
14
4
6
34
6
10

You can see from the output that forEach() statement works just like for loop but it is much more powerful simply because you can perform the looping in parallel without writing a single line of multi-threading code.

Here is the another forEach() method defined in the Iterable interface, you can use it directly without calling the stream() method because List, Set or Queue implements Collection and Iterable interface.

JDK 8 ForEach Example


Advantages of forEach() over for loop in Java 8 

There are several advantages of using forEach() statement over traditional for loop in Java 8 e.g.
  • More succinct code, sometimes just one liner
  • You can pass lambda expression, which gives you the immense flexibility to change what you do in the loop.
  • forEach looping can be made parallel with minimal effort e.g. without writing a single line of concurrent code, all you need to do is call parallelStream() method. 


Important points about forEach method
  1. forEach() method is defined at two places, on Iterable interface as well as on Stream class. which means list.forEach() and list.stream.forEach() both are valid.
  2. Prefer using forEach() with streams because streams are lazy and not evaluated until a terminal operation is called. 
  3. forEach() is a terminal operation, you cannot call any method on stream after this.
  4. When you run forEach() method on parallel stream the order on which elements are processed is not guaranteed, though you can use forEachOrdered() to impose ordering.
  5. forEach() method accepts a Consumer instance, which is a functional interface, that's why you can pass a lambda expression to it. 


That's all about how to use forEach() method to loop over Stream in Java. You can use this technique to go over any Collection, List, Set or Queue in Java. They all allow you to get a Stream and subsequently call the forEach() method on it. Remember, though, forEach() is a terminal operation and you cannot call another method after this. Don't re-use or pass around streams after calling any terminal operation on it e.g. forEach().


Related Java 8 Tutorials
If you are interested in learning more about new features of Java 8,here are my earlier articles covering some of the important concepts of Java 8:
  • 20 Examples of Date and Time in Java 8 (tutorial)
  • How to use Stream class in Java 8 (tutorial)
  • How to use filter() method in Java 8 (tutorial)
  • How to use forEach() method in Java 8 (example)
  • How to join String in Java 8 (example)
  • How to convert List to Map in Java 8 (solution)
  • How to use peek() method in Java 8 (example)
  • 5 Books to Learn Java 8 from Scratch (books)
  • How to convert stream to array in Java 8 (tutorial)
  • Java 8 Certification FAQ (guide)
  • Java 8 Mock Exams and Practice Test (test)

Thanks for reading this article so far. If you like this article then please share with your friends and colleagues. If you have any question, doubt, or feedback then please drop a comment and I'll try to answer your question.

2 comments :

ysden123 said...

Thanks for post!
In sample code "i ->: was transformed into "i ->"

Unknown said...

How java 8 iterable.forEach() is different with iterable.iterator().

Post a Comment