54

Consider the following scenario.

List<String> list = new ArrayList<>();

Now I added the String values for this list.

I used following ways to go each and every element in the list.

Option one- use for-each

for (String i : list) {
        System.out.println(i);
    } 

Option two- use Iterator

Iterator it=list.iterator();
while (it.hasNext()){
   System.out.println(it.next());
}

I just want to know is there any performance advantage if I use for-each instead of Iterator. And also is it a bad practice to use Iterator now a days in Java?

4

8 回答 8

101

for-each是使用的语法糖iterators(方法 2)。

iterators如果您需要在循环中修改集合,则可能需要使用。第一种方法将引发异常。

for (String i : list) {
    System.out.println(i);
    list.remove(i); // throws exception
} 

Iterator it=list.iterator();
while (it.hasNext()){
    System.out.println(it.next());
    it.remove(); // valid here
}
于 2013-08-29T10:46:02.443 回答
18

区别主要在于语法糖,除了 Iterator 可以从它正在迭代的 Collection 中删除项目。从技术上讲,增强的 for 循环允许您循环任何可迭代的内容,其中至少包括集合和数组。

不要担心性能差异。这种微优化是一种无关紧要的干扰。如果您需要随时删除项目,请使用迭代器。否则 for 循环往往会被更多地使用,因为它们更具可读性,即:

for (String s : stringList) { ... }

与:

for (Iterator<String> iter = stringList.iterator(); iter.hasNext(); ) {
  String s = iter.next();
  ...
}
于 2013-08-29T11:02:23.117 回答
12

for-each是一种高级循环结构。它在内部创建一个迭代器并迭代集合。使用实际的 Iterator 对象而不是for-each构造的唯一可能优势是您可以使用 Iterator 的方法(如.remove(). 在迭代时修改集合而不使用迭代器的方法将产生ConcurrentModificationException。

于 2013-08-29T10:59:59.600 回答
3

最好的方法是在 java 8 中,

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

这里有一些有用的链接。

  1. Java 8 Iterable.forEach() 与 foreach 循环

  2. http://www.javaworld.com/article/2461744/java-language/java-language-iterating-over-collections-in-java-8.html

  3. https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html

于 2015-04-21T08:12:07.057 回答
2

简单的答案:不,不。

在内部for-each循环创建一个Iterator遍历集合。

使用Iterator显式的优点是您可以访问Iterators 方法。

于 2013-08-29T10:45:05.843 回答
1

这是一个简单的代码片段,用于检查在 Java 版本 8 上执行的For-eachvs Iteratorvsfor遍历的性能。ArrayList<String>

        long MAX = 2000000;

        ArrayList<String> list = new ArrayList<>();

        for (long i = 0; i < MAX; i++) {

            list.add("" + i);
        }

        /**
         * Checking with for each iteration.
         */
        long A = System.currentTimeMillis();

        for (String data : list) {
            // System.out.println(data);
        }

        long B = System.currentTimeMillis();
        System.out.println(B - A + "ms");

        /**
         * Checking with Iterator method
         */

        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            iterator.next();
            // System.out.println(iterator.next());
        }

        long C = System.currentTimeMillis();
        System.out.println(C - B + "ms");

        /**
         * Checking with normal iteration.
         */
        for (int i = 0; i < MAX; i++) {
            list.get((int) (i % (MAX - i)));
            // System.out.println(list.get(i));
        }

        long D = System.currentTimeMillis();
        System.out.println(D - C + "ms");

平均输出值:

19ms
9ms
27ms

结果分析: Iterator (9ms) < For-each(19ms) < For(27ms)

这里Iterator的性能最好,性能For最低。然而For-each,性能介于两者之间。

于 2018-02-08T07:15:58.197 回答
0

If you want to replace items in your List, I would go old school with a for loop

for (int nIndex=0; nIndex < list.size(); nIndex++) {
  Obj obj = (Obj) list.get(nIndex);

  // update list item
  list.set(nIndex, obj2);
}
于 2014-10-14T04:30:30.750 回答
0

foreach无论如何在引擎盖下使用迭代器。它实际上只是语法糖。

考虑以下程序:

import java.util.List;
import java.util.ArrayList;

public class Whatever {
    private final List<Integer> list = new ArrayList<>();
    public void main() {
        for(Integer i : list) {
        }
    }
}

让我们用 编译它javac Whatever.java
并读取 的反汇编字节码main(),使用javap -c Whatever

public void main();
  Code:
     0: aload_0
     1: getfield      #4                  // Field list:Ljava/util/List;
     4: invokeinterface #5,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
     9: astore_1
    10: aload_1
    11: invokeinterface #6,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
    16: ifeq          32
    19: aload_1
    20: invokeinterface #7,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
    25: checkcast     #8                  // class java/lang/Integer
    28: astore_2
    29: goto          10
    32: return

我们可以看到foreach编译成一个程序:

  • 使用创建迭代器List.iterator()
  • If Iterator.hasNext(): 调用Iterator.next()并继续循环

至于“为什么这个无用的循环没有从编译后的代码中得到优化?我们可以看到它对列表项没有任何作用”:好吧,您可以编写.iterator()具有副作用的可迭代对象,或者这样.hasNext()有副作用或有意义的后果。

你可以很容易地想象一个表示来自数据库的可滚动查询的迭代可能会做一些戏剧性的事情.hasNext()(比如联系数据库,或者因为你已经到达结果集的末尾而关闭游标)。

因此,即使我们可以证明循环体中没有发生任何事情……但证明在我们迭代时没有发生任何有意义/后果性的事情会更加昂贵(难以处理?)。编译器必须将这个空循环体留在程序中。

我们所希望的最好的结果就是编译器警告。有趣的是,它javac -Xlint:all Whatever.java没有警告我们这个空循环体。IntelliJ IDEA 可以。诚然,我已经将 IntelliJ 配置为使用 Eclipse 编译器,但这可能不是原因。

在此处输入图像描述

于 2017-03-07T12:00:42.997 回答