【问题标题】:what is the advantage using iterator? [duplicate]使用迭代器有什么好处? [复制]
【发布时间】:2025-12-14 01:50:01
【问题描述】:
for(Element e : elementList)

for (Iterator<Element> itr = elementList.iterator(); itr.hasNext();)

第一个要简单得多。我想做第二个有什么优势或理由吗?

【问题讨论】:

  • 他们做同样的事情,当你想使用remove()方法时,你可以使用第二个。
  • 你测量了每个所花费的时间吗?这是一个技巧问题,其中一种方法有很多缓存命中而另一种方法有很多未命中?

标签: java loops


【解决方案1】:

它们在内部都使用了迭代器,唯一的区别是当你使用增强的for循环时代码更清晰更短。以下是 javadoc 关于两者的说法:

迭代一个集合比它需要的更丑陋。考虑以下方法,该方法采用一组计时器任务并取消它们:

void cancelAll(Collection<TimerTask> c) {
    for (Iterator<TimerTask> i = c.iterator(); i.hasNext(); )
        i.next().cancel();
}

迭代器很混乱。此外,这是犯错的机会。迭代器变量在每个循环中出现 3 次:这是两次出错的机会。 for-each 结构消除了混乱和出错的机会。下面是使用 for-each 构造的示例:

void cancelAll(Collection<TimerTask> c) {
    for (TimerTask t : c)
        t.cancel();
}

当您看到冒号 (:) 时,将其读作“in”。上面的循环读作“对于 c 中的每个 TimerTask t”。如您所见,for-each 构造与泛型完美结合。它保留了所有类型的安全性,同时消除了剩余的混乱。因为您不必声明迭代器,所以您不必为它提供通用声明。 (编译器会在您背后为您执行此操作,但您不必关心它。)

关于为什么我们应该使用 for-each 循环而不是迭代器的完整描述,请阅读以下内容:

http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html

【讨论】:

    【解决方案2】:

    第一种形式是在 Java 5 中引入的,第二种形式主要存在于该语言早期版本的遗留代码中。尽管如此,在某些情况下您仍然需要使用第二种形式;例如,如果循环需要能够在迭代时删除部分(或全部)元素,那么您需要有 itr 以便您可以调用它的 remove 方法。

    【讨论】:

      【解决方案3】:

      Iterator 可以 remove() 集合中的元素,这不能使用 for each 循环来完成

      【讨论】:

        【解决方案4】:

        没有性能差异。但是通过使用迭代器,您将有更多的功能可供使用。例如,您可以在循环中引用迭代器。这允许您执行一些操作,例如删除获取 ConcurrentModificationException 的集合项。

        您可以使用以下

        for (Iterator<Element> itr = elementList.iterator(); itr.hasNext();){
             if(o meets some condition){
                  itr.remove();
             }
        }
        

        但不是这个

           for(Element e : elementList){
                 if(o meets some condition){
                      elementList.remove(e);
                 }
            }
        

        但是,如果这种差异不打扰您,那么您可以使用让您感到舒适的那个。

        similar so question

        【讨论】:

          【解决方案5】:

          它们非常相似。考虑这段代码

          import java.util.Iterator;
          import java.util.ArrayList;
          
          public class IteratorTest {
          
            public static void main(String[] args){
          
              ArrayList<Object> list = new ArrayList();
              list.add(new Object());
              list.add(new Object());
          
              for(Object o : list) 
                System.out.println(o);
          
              for(Iterator<Object> itr = list.iterator();itr.hasNext();) 
                System.out.println(itr.next());
          
          
            }
          }
          

          然后我们使用它编译和反汇编它

          javap -c IteratorTest
          

          并为 main 方法获取以下字节码

            public static void main(java.lang.String[]);
              Code:
                 0: new           #2                  // class java/util/ArrayList
                 3: dup           
                 4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
                 7: astore_1      
                 8: aload_1       
                 9: new           #4                  // class java/lang/Object
                12: dup           
                13: invokespecial #1                  // Method java/lang/Object."<init>":()V
                16: invokevirtual #5                  // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
                19: pop           
                20: aload_1
                21: new           #4                  // class java/lang/Object
                24: dup           
                25: invokespecial #1                  // Method java/lang/Object."<init>":()V
                28: invokevirtual #5                  // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
                31: pop           
                32: aload_1       
                33: invokevirtual #6                  // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
                36: astore_2      
                37: aload_2       
                38: invokeinterface #7,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
                43: ifeq          63
                46: aload_2       
                47: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
                52: astore_3      
                53: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
                56: aload_3       
                57: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
                60: goto          37
                63: aload_1       
                64: invokevirtual #11                 // Method java/util/ArrayList.iterator:()Ljava/util/Iterator;
                67: astore_2      
                68: aload_2       
                69: invokeinterface #7,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
                74: ifeq          92
                77: getstatic     #9                  // Field java/lang/System.out:Ljava/io/PrintStream;
                80: aload_2       
                81: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
                86: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
                89: goto          68
                92: return        
          }
          

          第 32 到 60 行是第一个循环,第 63 到 89 行是第二个循环。您会注意到它们几乎相同 - 只是一些当地人的名字发生了变化并略有重新排序。

          因此,由于编译器为两个表达式生成相同的字节码,所以它们是相同的。

          【讨论】: