java—使用迭代器的优势是什么?

798qvoo8  于 2021-06-30  发布在  Java
关注(0)|答案(5)|浏览(311)

这个问题在这里已经有答案了

哪个更有效,for-each循环,还是迭代器(7个答案)
7年前关门了。

for(Element e : elementList)

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

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

hec6srdp

hec6srdp1#

没有性能差异。但是通过使用迭代器,您可以使用更多的功能。例如,可以在循环中引用迭代器。这允许您执行诸如删除集合项以获取 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);
         }
    }

但如果这种差异不困扰你,那么你可以用一个安慰你的孩子。
类似这样的问题

vktxenjb

vktxenjb2#

迭代器可以从集合中删除()元素,这不能使用for each循环来完成

8wtpewkr

8wtpewkr3#

它们非常相似。考虑一下这个代码

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行是第二个循环。你会注意到他们几乎是一样的-只是一些当地人的名字改变和轻微的重新排序。
因此,当编译器为这两个表达式生成相同的字节码时,它们是相同的。

b4lqfgs4

b4lqfgs44#

第一种形式是在Java5中引入的,第二种形式主要出现在该语言早期版本的遗留代码中。尽管如此,仍有一些情况需要使用第二种形式;例如,如果循环需要能够在元素被迭代时移除部分(或全部)元素,那么您需要 itr 所以你可以称之为 remove 方法。

puruo6ea

puruo6ea5#

在内部,它们都使用迭代器,唯一的区别是使用增强for循环时代码更清晰、更简短。以下是javadoc对这两者的看法:
对集合进行迭代比它需要的更糟糕。考虑以下方法,该方法获取计时器任务的集合并取消它们:

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

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

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

当您看到冒号(:)时,将其读作“in”。上面的循环读作“for each timertask t in c”。如您所见,for each构造与泛型完美地结合在一起。它保留了所有类型的安全性,同时消除了剩余的混乱。因为不必声明迭代器,所以不必为它提供泛型声明(编译器会在你背后为你做这件事,但你不必担心。)
关于为什么我们应该使用for each循环而不是iterator的完整描述,请阅读以下内容:
http://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html

相关问题