为什么Java 8引入了iterable.forEach()循环(即使每个都有)?

Pra*_*lam 4 foreach lambda java-8

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

Q1-为什么要迭代.forEach()?

Q2。在哪里使用?

Q3。对于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);
    }
}**
Run Code Online (Sandbox Code Playgroud)

a.l*_*.l. 5

这只是一个美味的问题。如果您想要更实用的功能,请使用forEach,但在您的情况下,传统的 for-each 循环很好。事实上,有两件事for-loop支持但forEach不支持:

  1. 流量控制关键字,如continue, break,return
  2. Checked exception


Hol*_*ger 5

通过函数式编程的启发新的API的总体思路是要表达什么做的,而不是如何去做。即使使用简化的for-each循环,

for(Integer i: myList) System.out.println("Value::"+i);
Run Code Online (Sandbox Code Playgroud)

它只是“获取Iterator实例hasNext()next()在其上反复调用”指令的语法糖。

相反,当使用

myList.forEach(i -> System.out.println("Value::"+i));
Run Code Online (Sandbox Code Playgroud)

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

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

例如,ArrayListint不构建Iterator实例的情况下执行基于-index的循环,Collections.emptyList()除了检查Consumer抵制nullTreeSetresp)之外,什么都不做。它的支持TreeMap遍历入口链接,这比其Iterator必须支持remove操作的实现要简单得多,依此类推。

专用的forEach实现是否可以补偿与Consumer构造相关的开销(如果有的话)(请注意,并非每个lambda表达式都会创建一个新对象),这是无法预测的,因此对此的假设不应驱动软件设计。性能差异通常可以忽略不计。

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


Arn*_*lec 1

forEach 已被创建为使用 lambda 语法:

myList.forEach(System.out::println);
Run Code Online (Sandbox Code Playgroud)

或者

myList.forEach(e->System.out.println(e));
Run Code Online (Sandbox Code Playgroud)

这就是函数式接口的全部目的