8

I'm not able to understand why java 8 has forEach loop and taking the Consumer functional interface as parameter. Even though we can do the same task using traditional for each loop without creating any extra overhead to create a class implements that from Consumer and implements a method and then pass this as reference to the forEach(). Although there is lambda expression to make it short.

Q1- why iterable.forEach()?

Q2. Where to use it?

Q3. which one is faster traditional for each of Java 8 forEach()?

Sample:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.function.Consumer;
import java.lang.Integer;

public class ForEachExample {

    public static void main(String[] args) {

        //creating sample Collection
        List<Integer> myList = new ArrayList<Integer>();
        for(int i=0; i<10; i++) myList.add(i);

        //traversing using Iterator
        Iterator<Integer> it = myList.iterator();
        while(it.hasNext()){
            Integer i = it.next();
            System.out.println("Iterator Value::"+i);
        }

        //traversing through forEach method of Iterable with anonymous class
        myList.forEach(new Consumer<Integer>() {

            public void accept(Integer t) {
                System.out.println("forEach anonymous class Value::"+t);
            }

        });

        //traversing with Consumer interface implementation
        MyConsumer action = new MyConsumer();
        myList.forEach(action);

    }

}

//Consumer implementation that can be reused
**class MyConsumer implements Consumer<Integer>{
    public void accept(Integer t) {
        System.out.println("Consumer impl Value::"+t);
    }
}**
janith1024
  • 1,042
  • 3
  • 12
  • 25
Pravin Mangalam
  • 151
  • 1
  • 2
  • 8
  • one reason is clarity of intent and concision: you can write your loop like this: `myList.forEach(System.out::println);` Many things are compatible with the `Consumer` interface, so you can replace many loops with a `forEach` without needing intermediate variable – njzk2 Jun 25 '18 at 04:26
  • iterable.forEach() can only print the data/list. even we can not access the outer variable inside the lambdaexp. or loop and we can not perform any business operation by accessing the outer data. but still to just print the values it is necessary to use iterable.forEach()? – Pravin Mangalam Jun 25 '18 at 04:42
  • I consider not being able to access outer data is a feature, forcing developers to pay attention to side effects – njzk2 Jun 25 '18 at 04:46
  • What do you mean with “outer data”? You *can* access variables from the surrounding context from a lambda expression. In case of local variables they have to be effectively final. By the way, the standard idiom for looping over an iterable for your example is `for(Integer i: myList) System.out.println("Iterator Value::"+i);` – Holger Jun 25 '18 at 09:55

4 Answers4

6

The general idea of the new APIs inspired by Functional Programming is to express what to do instead of how to do it. Even when using the simplified for-each loop,

for(Integer i: myList) System.out.println("Value::"+i);

it’s just syntactic sugar for the instructions “acquire an Iterator instance and call repeatedly hasNext() and next() on it”.

In contrast, when using

myList.forEach(i -> System.out.println("Value::"+i));

you provide an action, to be applied to each element, but don’t specify how to do it. The default implementation will just perform the Iterator based loop, but actual Iterable implementations may override it to perform the operation differently.

Note that a lot of Iterator implementations are performing checks twice, once in hasNext(), then again in next() as there is no guaranty that the caller did hasNext() first, to throw a NoSuchElementException if there is no next element. Sometimes this even implies holding additional state within the Iterator instance to remember whether a particular “fetch-next” operation has been performed already. A dedicated forEach implementation can be straight-forward, more efficient while being simpler in code.

For example, ArrayList performs an int-index based loop without constructing an Iterator instance, Collections.emptyList() does nothing but checking the Consumer against null, TreeSet resp. its backing TreeMap traverses entry links, which is much simpler than its Iterator implementation which has to support the remove operation, and so on.

Whether a dedicated forEach implementation may compensate the Consumer construction related overhead, if there is one (mind that not every lambda expression creates a new object), is not predictable and assumptions about that should not drive the software design. More than often, the performance differences are negligible.

But there can be semantic differences too. When using one of the collections returned by Collections.synchronized…, an Iterator based loop can not provide consistency guarantees when the underlying collection is modified by another thread. The application would need to lock on the collection manually and have to care to use the right object instance, e.g. if the iterable is a subList or subSet. In contrast, the specialized forEach(Consumer) locks correctly during the entire operation, whereas the operation itself is as simple as delegating to the source’s forEach method, to still perform it in the optimal way according to the actual underlying collection.

Holger
  • 285,553
  • 42
  • 434
  • 765
5

It just a tasty problem. If you want something more functional, use forEach, but in your case, the traditional for-each loop is good. In fact, there are two things for-loop supports but forEach not:

  1. flow control keywords like continue, break, return
  2. Checked exception
a.l.
  • 1,085
  • 12
  • 29
2

Q1- why iterable.forEach()?

It introduce to reduce the lines of code. Your loop can see in following as old way and new way

old way

   for (Integer t : myList) {
        System.out.println("forEach old way Value::"+t);
    }

new way

   myList.forEach(t ->System.out.println("forEach lambda way::"+t));

Q2. Where to use it?

Any where you want to iterate over the collection.

Q3. which one is faster traditional for each of Java 8 forEach()?

Older way and new way both there is no big performance difference. But if you use stream to iterate it has some latency than old for each.

janith1024
  • 1,042
  • 3
  • 12
  • 25
1

forEach has been created to use lambda syntax :

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

or

myList.forEach(e->System.out.println(e));

This is the whole purpose of functional interface