1. イテレーター Iterator
インターフェース: Iterator
public interface Iterator<E>{ boolean hasNext(); E next(); void remove(); }
Iterator インターフェース API を見ると、これがコレクションを反復するためのイテレーターであることがわかります。イテレーターを使用すると、呼び出し元は、明確に定義されたセマンティクスを使用して、反復中にイテレーターが指すコレクションから要素を削除できます。
特に注目に値するのは、この反復子の Remove() メソッドの使用です。反復子によって返された最後の要素 (オプションの操作) を、反復子が指すコレクションから削除します。このメソッドは、next の呼び出しごとに 1 回だけ呼び出すことができます。このメソッド (remove メソッド) の呼び出し以外の方法で反復中にイテレーターが指すコレクションが変更された場合、イテレーターの動作は未定義です。インターフェイス設計者は、Iterator
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; public class ItaratorTest { public static void main(String[] args) { Collection<String> list = new ArrayList<String>(); list.add("Android"); list.add("IOS"); list.add("Windows Mobile"); Iterator<String> iterator = list.iterator(); while (iterator.hasNext()) { String lang = iterator.next(); list.remove(lang);//will throw ConcurrentModificationException } } }
このコードは、実行中に ConcurrentModificationException 例外をスローします。これは、イテレータの実行中に要素を削除するためにイテレータの Remove() メソッドを使用せず、ArrayList の Remove() メソッドを使用するためです。イテレータが指すコレクションを変更します。これはイテレータの設計原則に違反するため、例外が発生します。
報告された例外は次のとおりです:
Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) at java.util.ArrayList$Itr.next(ArrayList.java:831) at Text.ItaratorTest.main(ItaratorTest.java:17)
2. for-each ループと反復子 Iterator
Java5 以降、Java には for-each ループがあり、コレクションと配列をループするために使用できます。 Foreach ループを使用すると、従来の for ループでインデックスを維持したり、イテレータ / ListIterator (ArrayList のイテレータ実装) を使用するときに while ループで hasNext() メソッドを呼び出すことなく、コレクションを反復処理できます。 for-each ループにより、コレクションまたは配列を走査するプロセスが簡素化されます。ただし、foreach ループを使用する場合は注意すべき点が 2 つあります。
foreach ループを使用するオブジェクトは Iterable
次の例を参照してください:
import java.util.ArrayList; public class ForeachTest1 { public static void main(String args[]) { CustomCollection<String> myCollection = new CustomCollection<String>(); myCollection.add("Java"); myCollection.add("Scala"); myCollection.add("Groovy"); // What does this code will do, print language, throw exception or // compile time error for (String language : myCollection) { System.out.println(language); } } private class CustomCollection<T> { private ArrayList<T> bucket; public CustomCollection() { bucket = new ArrayList(); } public int size() { return bucket.size(); } public boolean isEmpty() { return bucket.isEmpty(); } public boolean contains(T o) { return bucket.contains(o); } public boolean add(T e) { return bucket.add(e); } public boolean remove(T o) { return bucket.remove(o); } } }
これは、コード内の CustomCollection クラスが Iterable
Exception in thread "main" java.lang.Error: Unresolved compilation problem: Can only iterate over an array or an instance of java.lang.Iterable at Text.ForeachTest1.main(ForeachTest1.java:15)
実際、Eclipse は、このコードを記述した後、コンパイルでエラーを見つけるまで待つ必要はありません。配列またはインスタンスのみを反復処理できます。 java.lang.Iterable
上記の例から再度確認できることは、foreach ループは Iterable
import java.util.AbstractCollection; import java.util.ArrayList; import java.util.Iterator; public class ForeachTest { public static void main(String args[]) { CustomCollection<String> myCollection = new CustomCollection<String>(); myCollection.add("Java"); myCollection.add("Scala"); myCollection.add("Groovy"); for (String language : myCollection) { System.out.println(language); } } private static class CustomCollection<T> extends AbstractCollection<T> { private ArrayList<T> bucket; public CustomCollection() { bucket = new ArrayList(); } public int size() { return bucket.size(); } public boolean isEmpty() { return bucket.isEmpty(); } public boolean contains(Object o) { return bucket.contains(o); } public boolean add(T e) { return bucket.add(e); } public boolean remove(Object o) { return bucket.remove(o); } @Override public Iterator<T> iterator() { // TODO Auto-generated method stub return bucket.iterator(); } } }
2. foreach ループの内部実装も Iterator に依存します
foreach ループが内部実装として Iterator を使用するという事実を確認するために、この記事の最初の例を引き続き使用します。検証用:
public class ItaratorTest { public static void main(String[] args) { Collection<String> list = new ArrayList<String>(); list.add("Android"); list.add("IOS"); list.add("Windows Mobile"); // example1 // Iterator<String> iterator = list.iterator(); // while (iterator.hasNext()) { // String lang = iterator.next(); // list.remove(lang); // } // example 2 for (String language : list) { list.remove(language); } } }
プログラムの実行時に報告される例外:
Exception in thread "main" java.util.ConcurrentModificationException at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859) at java.util.ArrayList$Itr.next(ArrayList.java:831) at Text.ItaratorTest.main(ItaratorTest.java:22)
この例外は、コレクションを走査するために for-each ループ内で Iterator が使用されていること、および変更をチェックする Iterator.next() を呼び出していることを示しています (の要素)、ConcurrentModificationException をスローします。
概要:
コレクションを走査するときに、走査中にコレクションを変更したい場合は、Iterator/listIterator を使用して変更する必要があります。そうしないと、「未確定の結果」が発生する可能性があります。
foreach ループはイテレータを通じて実装され、foreach ループを使用するオブジェクトは Iterable インターフェイスを実装する必要があります