Java 对于每个vs迭代器。哪一个是更好的选择

Java 对于每个vs迭代器。哪一个是更好的选择,java,foreach,iterator,Java,Foreach,Iterator,考虑以下场景 List<String> list = new ArrayList<>(); 选项二-使用迭代器 Iterator it=list.iterator(); while (it.hasNext()){ System.out.println(it.next()); } 我只想知道如果我对每个使用而不是迭代器,是否有性能优势。现在在Java中使用迭代器也是一种不好的做法吗?简单的答案:否和否 在内部,for each循环创建一个迭代器,对集合进行迭代 显

考虑以下场景

List<String> list = new ArrayList<>();
选项二-使用迭代器

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

我只想知道如果我对每个使用
而不是
迭代器
,是否有性能优势。现在在Java中使用迭代器也是一种不好的做法吗?

简单的答案:否和否

在内部,
for each
循环创建一个
迭代器
,对集合进行迭代


显式使用
迭代器的优点是,您可以访问
迭代器的方法。

对于每个
都是使用
迭代器的语法糖(方法2)

如果需要修改循环中的集合,可能需要使用迭代器。第一种方法将抛出异常

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
}

每个
都是高级循环结构。它在内部创建一个迭代器并在集合上进行迭代。对于每个
构造,使用实际迭代器对象而不是
对象的唯一可能优势是,您可以使用迭代器的方法(如
.remove()
)修改集合。在迭代过程中不使用迭代器的方法修改集合将产生一个

差异主要是语法上的差异,除了迭代器可以从它正在迭代的集合中删除项之外。从技术上讲,增强的for循环允许您循环任何可执行的内容,至少包括集合和数组

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

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

for(迭代器iter=stringList.Iterator();iter.hasNext();){
字符串s=iter.next();
...
}

如果您想替换列表中的项目,我会使用for循环进行旧式学习

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

  // update list item
  list.set(nIndex, obj2);
}
for(int-nIndex=0;nIndex
最好的方法是在java 8中

list.forEach(System.out::println);
这里有一些有用的链接


  • 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) {
            }
        }
    }
    
    我们可以看到,
    foreach
    编译成一个程序,该程序:

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

    至于“为什么这个无用的循环不能从编译后的代码中得到优化?我们可以看到它对列表项没有任何作用”:那么,您可以对iterable进行编码,使
    .iterator()
    产生副作用,或者
    .hasNext()
    产生副作用或有意义的后果

    您可以很容易地想象,表示来自数据库的可滚动查询的iterable可能会在
    .hasNext()
    上做一些引人注目的事情(比如联系数据库,或者因为已到达结果集的末尾而关闭光标)

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

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


    这里是一个简单的代码片段,用于检查每个
    迭代器的
    的性能,用于遍历在Java版本8上执行的
    ArrayList

            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");
    
    结果分析:
    迭代器
    (9ms)
    (19ms)
    (27ms)

    这里,
    迭代器
    的性能最好
    For
    的性能最低。然而,
    对于每个
    性能而言,都介于两者之间


    我认为对于每一次使用,迭代或可能的重复都不能“将”导致ConcurrentModificationExceptionOne混乱如果在内部为每个使用迭代器增强,为什么在迭代时删除元素会受到限制?@shaun,因为您没有访问权限:)当然最好记住,从循环的集合中添加/删除项不是好的做法,出于您突出显示的原因。为什么您认为使用list.foreach()更好?在这样的feaeach()方法中,您不能修改外部变量,必须将其复制为final或将其包装在数组中。但为什么不需要在代码中导入迭代器类?@Dakatine,因为导入是由编译器隐式完成的。
    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) {
            }
        }
    }
    
    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
    
            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