为什么Java 8引入了iterable.forEach()循环(即使每个都有)? [英] Why java 8 introduces iterable.forEach() loop even though it has for each?

查看:97
本文介绍了为什么Java 8引入了iterable.forEach()循环(即使每个都有)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不明白为什么Java 8具有forEach循环并以Consumer功能接口作为参数.即使我们可以对每个循环使用传统方法执行相同的任务,而无需创建任何额外的开销来创建一个类,该类从Consumer中实现该类并实现一个方法,然后将其作为对forEach()的引用.尽管有lambda表达式可以使它简短.

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-为什么要迭代.forEach()?

Q1- why iterable.forEach()?

Q2.在哪里使用?

Q3.对于Java 8 forEach()来说,哪一种是传统上最快的?

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

示例:

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);
    }
}**

推荐答案

受函数式编程启发的新API的一般思想是表达要做什么而不是如何做做到这一点.即使使用简化的for-each循环,

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

这只是获取一个Iterator实例并在其上反复调用hasNext()next()"指令的语法糖.

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

相反,使用时

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

您提供了要应用于每个元素的操作,但未指定操作方法. default实现只会执行基于Iterator的循环,但是实际的Iterable实现可能会覆盖它以不同方式执行操作.

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.

请注意,许多Iterator实现都执行两次检查,一次是在hasNext()中,然后是再次在next()中,因为没有保证调用者首先进行hasNext(),如果没有下一个元素.有时,这甚至意味着在Iterator实例中保留其他状态,以记住是否已经执行了特定的提取-下一个"操作.专用的forEach实现可以直接,更高效,同时使代码更简单.

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.

例如,ArrayList在不构造Iterator实例的情况下执行基于int -index的循环,Collections.emptyList()除了对nullTreeSet分别检查Consumer之外,不执行任何操作.它的后方TreeMap遍历入口链接,这比其必须支持remove操作的Iterator实现要简单得多,等等.

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.

如果有一个(请注意,不是并非每个lambda,表达式会创建一个新对象),这是不可预测的,对此的假设不应驱动软件设计.性能差异通常可以忽略不计.

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.

但是在语义上也可能存在差异.使用Collections.synchronized…返回的集合之一时,当基础集合被另一个线程修改时,基于Iterator的循环不能提供一致性保证.应用程序需要手动锁定集合,并且必须注意使用正确的对象实例,例如如果iterable是 subList subSet .相反,专门的forEach(Consumer)在整个操作过程中正确锁定,而操作本身就像委派源代码的forEach方法一样简单,仍然可以根据实际基础集合以最佳方式执行该操作.

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.

这篇关于为什么Java 8引入了iterable.forEach()循环(即使每个都有)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆