サーチ…


前書き

java.util.Iteratorは、Iteratorデザインパターンを実装するオブジェクトの標準Java SEインターフェイスです。 java.lang.Iterableインタフェースは、イテレータを提供できるオブジェクト用です。

備考

Java配列はIterableを実装しませんが、 for -eachループを使用して配列全体を反復することは可能です。反復は、バックグラウンドでアクセスできないインデックスを使用してJVMによって行われます。

forループでIterableを使う

Iterable<>インタフェースを実装するクラスは、 forループで使用できます。これは、オブジェクトからイテレータを取得し、それを使ってすべての要素を連続に取得するための構文砂糖です。コードをより明確にし、書込みを速くし、エラーを起こしにくくします。

public class UsingIterable {

    public static void main(String[] args) {
        List<Integer> intList = Arrays.asList(1,2,3,4,5,6,7);
        
        // List extends Collection, Collection extends Iterable
        Iterable<Integer> iterable = intList;
        
        // foreach-like loop
        for (Integer i: iterable) {
            System.out.println(i);
        }
        
        // pre java 5 way of iterating loops
        for(Iterator<Integer> i = iterable.iterator(); i.hasNext(); ) {
            Integer item = i.next();
            System.out.println(item);
        }
    }
}

生のイテレータを使用する

foreachループ(または "extended for loop")を使用するのは簡単ですが、イテレータを直接使用すると有益なことがあります。たとえば、コンマ区切り値の束を出力したいが、最後の項目にコンマをつけたくない場合は、次のようにします。

List<String> yourData = //...
Iterator<String> iterator = yourData.iterator();
while (iterator.hasNext()){
    // next() "moves" the iterator to the next entry and returns it's value.
    String entry = iterator.next();
    System.out.print(entry);
    if (iterator.hasNext()){
        // If the iterator has another element after the current one:
        System.out.print(",");
    }
}

isLastEntry変数を使用するか、ループインデックスを使用して計算するよりもはるかに簡単で分かりやすくなります。

独自のIterableを作成する。

どのインタフェースでも独自のIterableを作成するには、インタフェースに抽象メソッドを実装するだけです。 Iterableにはiterator()と呼ばれるものが1つしかありません。しかし、そのリターン型Iteratorはそれ自体、3つの抽象メソッドを持つインタフェースです。コレクションに関連付けられたイテレータを返すことも、独自のカスタム実装を作成することもできます。

public static class Alphabet implements Iterable<Character> {

    @Override
    public Iterator<Character> iterator() {
        return new Iterator<Character>() {
            char letter = 'a';

            @Override
            public boolean hasNext() {
                return letter <= 'z';
            }

            @Override
            public Character next() {
                return letter++;
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException("Doesn't make sense to remove a letter");
            }
        };
    }
}

使用するには:

public static void main(String[] args) {
    for(char c : new Alphabet()) {
        System.out.println("c = " + c);
    }
}

新しいIteratorは、最初のアイテムを指し示す状態でなければなりませんIteratorへの各呼び出しは、次の状態を指すように状態を更新します。 hasNext()はイテレータが最後にあるかどうかをチェックします。イテレータが変更可能なコレクションに接続されている場合、イテレータのオプションのremove()メソッドが実装され、現在のコレクションからポイントされているアイテムを削除できます。

イテレータを使用した要素の削除

Iterator.remove()メソッドは、 Iterator.next()への以前の呼び出しによって返された要素を削除するオプションのメソッドです。たとえば、次のコードは文字列のリストを作成し、すべての空の文字列を削除します。

List<String> names = new ArrayList<>();
names.add("name 1");
names.add("name 2");
names.add("");
names.add("name 3");
names.add("");
System.out.println("Old Size : " + names.size());
Iterator<String> it = names.iterator();
while (it.hasNext()) {
  String el = it.next();
  if (el.equals("")) {
    it.remove();
  }
}
System.out.println("New Size : " + names.size());

出力:

Old Size : 5
New Size : 3

上のコードは、典型的なコレクションを反復しながら要素を削除する安全な方法です。代わりに、次のようにコレクションから要素を削除しようとします。

for (String el: names) {
    if (el.equals("")) {
        names.remove(el); // WRONG!
    }
}

イテレータにフェイル・ファスト・イテレータ・セマンティクスを提供する典型的なコレクション( ArrayListなど)は、 ConcurrentModificationExceptionをスローします。

remove()メソッドは、 next()呼び出しの後にのみ呼び出されます(一度)。 next()呼び出す前に呼び出された場合、またはnext()呼び出しの後に2回呼び出された場合、 remove()呼び出しはIllegalStateExceptionをスローします。

remove操作はオプションの操作として説明されています 。つまり、すべてのイテレータで許可されるわけではありません。サポートされていない例には、不変なコレクションのイテレーター、コレクションの読み取り専用のビュー、固定サイズのコレクションなどがあります。イテレータが削除をサポートしていないときにremove()が呼び出されると、 UnsupportedOperationExceptionがスローされます。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow