for(Element e : elementList)
for (Iterator<Element> itr = elementList.iterator(); itr.hasNext();)
最初のものははるかに簡単です。2つ目をやりたい理由や利点はありますか?
内部的にはどちらもイテレータを使用していますが、唯一の違いは、強化された for ループを使用すると、コードがより明確で短くなることです。両方についてjavadocが言っていることは次のとおりです。
コレクションの反復処理は、必要以上に醜いものです。タイマー タスクのコレクションを取得し、それらをキャンセルする次のメソッドを検討してください。
void cancelAll(Collection<TimerTask> c) {
for (Iterator<TimerTask> i = c.iterator(); i.hasNext(); )
i.next().cancel();
}
イテレータは雑然としています。さらに、それはエラーの機会でもあります。iterator 変数は各ループで 3 回発生します。つまり、2 回間違える可能性があります。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 で導入され、2 番目の形式はほとんどが以前のバージョンの言語のレガシー コードに見られます。それでもなお、2 番目の形式を使用する必要がある状況がいくつかあります。たとえば、ループが繰り返されるときに要素の一部 (またはすべて) を削除できる必要がある場合は、そのメソッドitr
を呼び出すことができるようにする必要があります。remove
イテレーターは collection から要素をremove()できますが、これは for each ループを使用して行うことはできません
それらは非常に同じです。このコードを検討してください
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 は 2 番目のループです。一部のローカルの名前が変更され、わずかに並べ替えられているだけで、ほとんど同じであることがわかります。
したがって、コンパイラは 2 つの式に対して同じバイトコードを生成するため、それらは同じです。
性能差はありません。しかし、反復子を使用することで、より多くの機能を使用できるようになります。たとえば、ループ内で Iterator を参照できます。これにより、コレクション アイテムを削除して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);
}
}
ただし、この違いが気にならない場合は、快適なものを使用できます。