for(Element e : elementList)
for (Iterator<Element> itr = elementList.iterator(); itr.hasNext();)
第一个要简单得多。我想做第二个有什么优势或理由吗?
它们在内部都使用迭代器,唯一的区别是使用增强的 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
第一种形式是在 Java 5 中引入的,第二种形式主要存在于该语言早期版本的遗留代码中。尽管如此,在某些情况下您仍然需要使用第二种形式;例如,如果循环需要能够在迭代时删除部分(或全部)元素,那么您需要拥有itr
这样才能调用它的remove
方法。
没有性能差异。但是通过使用迭代器,您将有更多的功能可以使用。例如,您可以在循环中引用迭代器。这使您可以执行诸如删除收集项目之类的操作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);
}
}
但是,如果这种差异不打扰您,那么您可以使用让您感到舒适的那个。
它们非常相似。考虑这段代码
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
并获取以下主要方法的字节码
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 行是第二个循环。您会注意到它们几乎相同 - 只是一些当地人的名字发生了变化并略有重新排序。
因此,由于编译器为两个表达式生成相同的字节码,所以它们是相同的。