「 ArrayListでイテレータを使用する必要はありますか? 」という質問に対する回答を読んでいました。
答えとして、ユーザーは次のようなことを述べました。「ArrayListsを使用したイテレーターの大きなユースケースは、反復中に要素を削除する場合です」。
これは、JavaのArrayListのremoveメソッドを使用しても実現できます。私の質問は、ArrayListにイテレータが必要な理由ですか?
コードを考慮してください:
import Java.util.*;
public class ocajp66 {
public static void main(String[] args) {
ArrayList a = new ArrayList();
for (int i = 0; i < 10; i++) {
a.add(i);
}
System.out.printf("BEFORE ITERATOR\n");
for (int i = 0; i < a.size(); i++) {
System.out.printf("I:%d\n", a.get(i));
}
System.out.printf("AFTER ITERATOR\n");
Iterator i = a.iterator();
while (i.hasNext()) {
System.out.printf("I:%d\n", i.next());
}
}
}
誰もイテレータの重要性を説明できますか?コードで説明していただければ素晴らしいと思います。
あなたが述べたように、イテレータは、配列の内容を反復しながら、ものを削除したいときに使用されます。イテレータを使用せずにforループを使用し、その内部でremoveメソッドを使用すると、反復処理中に配列の内容が変化するため、例外が発生します。例:forループの開始時の配列サイズは10であると思われるかもしれませんが、ものを削除するとそれは当てはまりません。
iterator()
メソッドがなくてもArrayList
- like APIが機能することは明らかです。ただし、ArrayList
はCollection
であり、iterator()
メソッドはCollection
インターフェースで定義されています... ArrayList
- has実装します。
ArrayList
から削除することについてのポイントは、インデックス付けによってそれを行うには、いくつかの考えが必要であるということです:
_ for (int i = 0;
i < a.size(); // Hoist this at your peril
i++) {
if (a.get(i) == something) {
a.remove(i);
i--; // Leave this out at your peril
}
}
_
そして、ループから呼び出されたメソッドのリスト要素を削除する必要がある場合はさらに悪化します... 'メソッドは、呼び出し元がループインデックスを調整できるように要素を削除したと言う必要があるためです。
iterator
でArrayList
が良い理由の3番目の理由は、Java 5のfor (type var : iterable) ...
]構文を使用できることです。
一番下の行は、持っているArrayList
インスタンスでイテレータを使用しないことです。したくない場合は、しないでください。
これは、必要な結果をさまざまな方法で取得する方法の例です。この種の冗長性はJavaに固有のものではありません。
この構文は、Javaの非常に初期のバージョンで導入されました。 for {}ループの通常のJava配列を反復処理します。これは、Java配列は固定長であるため、 "Index Out of Bounds"なので一般に安全です。例外は不可能です。
この構文は、ArrayListを導入したCollections APIの導入後のJavaの以降のリリースを反映しています。 Collectionインターフェイスを実装するクラスは、前述のとおり、Iteratorを実装する必要がありますが、使用する必要はありません。これは{}ループではありませんが、ここでの危険はArrayListsが固定サイズではないことです。 forループの本体で縮小すると、例外が発生する可能性があります。
この構文は、Javaの以降のリリースでもリリースされました。拡張forループと呼ばれます。 Iterableインターフェイスを実装してIteratorを提供するコレクションクラスは、この構文を利用できます。これにより、イテレータを明示的にインスタンス化する必要なく、コレクション内のアイテムを反復処理できます。 JavaFXアプリケーションでこれを使用するお気に入りの方法は、多数のコントロールをループしてプロパティを値に設定することです。 TextFieldsのグループのコンテンツをリセットするには:
for (TextField tf : new TextField[] { txtf1, txtf2, txtf3, txtfa, txtfb, txtfc}) {
tf.setText("");
}
Iteratorはいつでも明示的にインスタンス化できます。これは、コレクションのサイズが(コレクションの独自のメソッドから)変更されている場合に使用しても安全です。 Iteratorは、コアJava言語の機能よりもIterableインターフェースのプロパティに近いと言えます。しかし、言語のような機能(拡張機能ではforループ)後でJavaリリース。
これらの構造は冗長性を提供しますが、同一ではありません。特定の時間に特に役立つように、それぞれに微妙な違いがあります。すべてを使用する必要があります。
Q:ArrayListにイテレータが必要なのはなぜですか?
コードで示したように、イテレータなしでArrayListのコア操作を繰り返し実行できます。しかし、機能を備えているのは素晴らしいことです。
Q:誰でもイテレータの重要性を説明できますか?
その設計上の価値に加えて、私が見ることができるのは、フェイルファースト機能です。 ArrayList documentation からこの段落を引用します。
このクラスのイテレータおよびlistIteratorメソッドによって返されるイテレータは、fail-fast:イテレータの作成後、リストが構造的に変更された場合、イテレータ自体のremoveまたはaddメソッドを介して以外は、イテレータはConcurrentModificationExceptionをスローします。したがって、同時変更に直面して、イテレータは、将来の未定の時点でarbitrary意的で非決定的な動作を危険にさらすのではなく、迅速かつクリーンに失敗します。
コードを探していたので、実際にはArrayListのイテレータの実装を確認できます: ArrayList.Java 。
質問に対して、list.remove()
の代わりにiterator.remove()
メソッドを使用すると、IndexOutOfBoundsException
がスローされます。
list.remove()
は、削除する特定のオブジェクト/インデックスを見つけたらbreak
ステートメントを入れて、例外なしでループから終了するように使用すると安全です(IndexOutOfBoundsException
)
次のイテレータコードはまだスローできますConcurrentModificationException
synchronized環境でイテレータEVENを使用する場合。
List<String> empNames = new ArrayList<String>();
synchronized (empNames) {
Iterator<String> iterator = empNames.iterator();
while (iterator.hasNext()) {
iterator.next();
empNames.add("Another Name"); // throws
// ConcurrentModificationException
}
}