1. イテレータが誕生した背景

についてはすでによくご存知ですHashSet。レッスンを読むだけでなく、それを本当に調べたなら、次の質問をするべきです。

すべての HashSet 要素のリストを画面に表示するにはどうすればよいですか? 結局のところ、インターフェイスにはメソッドがありませget()set()

HashSetこの制限に直面しているのは私だけではありません。に加えてHashSet、要素には順序が定義されていないため、インデックスによる要素の取得を許可しないコレクションが他にもたくさんあります。

長年にわたり、プログラマーはグラフやツリーなどの複雑なデータ構造を多数発明してきました。またはリストのリスト。

多くのコンテナでは、新しい要素が追加されるか、既存の要素が削除されると、要素の順序が変更されます。たとえば、リストには要素が特定の順序で格納され、新しい要素が追加されると、ほとんどの場合リストの中央に挿入されます。

また、要素を格納するコンテナはあるものの、固定された順序ではないという状況も発生します。

ここで、そのようなコレクションのすべての要素を配列またはリストにコピーするとします。すべての要素を取得する必要があります。要素を反復する順序は気にしません。重要なのは、同じ要素を複数回反復しないことです。どうやってそれを行うのでしょうか?


2. コレクションのイテレータ

イテレータは、上記の問題の解決策として提案されました。

イテレータはコレクションに関連付けられた特別なオブジェクトであり、コレクションのすべての要素を繰り返すことなく走査するのに役立ちます。

次のコードを使用して、任意のコレクションのイテレータを取得できます。

Iterator<Type> it = name.iterator();

ここでname、 はコレクション変数の名前、Typeはコレクションの要素の型、iterator()はコレクションのメソッドの 1 つ、itは反復子変数の名前です。

イテレータ オブジェクトには 3 つのメソッドがあります。

方法 説明
Type next()
コレクション内の次の要素を返します
boolean hasNext()
まだ通過していない要素があるかどうかを確認します
void remove()
コレクションの現在の要素を削除します

これらのメソッドは、Scanner クラスのnextInt)およびhasNextInt()メソッドに似ています。

このnext()メソッドは、反復子を取得したコレクションの次の要素を返します。

このhasNext()メソッドは、反復子がまだ返していない追加要素がコレクションにあるかどうかを確認します。

のすべての要素を表示する方法は次のとおりですHashSet

コード ノート
HashSet<String> set = new HashSet<String>();

set.add("Hallo");
set.add("Hello");
set.add("Hola");
set.add("Bonjour");
set.add("Ciao");
set.add("Namaste");

Iterator<String> it = set.iterator();
while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}
HashSet要素を格納するオブジェクトを作成しますString


さまざまな言語の挨拶をset変数に追加します。




セットの反復子オブジェクトを取得しますset
要素が残っている限り

次の要素を取得
画面上に要素を表示


3.For-eachループ

イテレータの主な欠点は、コードがforループを使用する場合よりも煩雑になることです。

for比較するために、ループとイテレータを使用してリストを表示してみましょう。

イテレーター forループ
ArrayList<String> list = new ArrayList<String>();

Iterator<String> it = list.iterator();
while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();

for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);
   System.out.println(str);
}

はい、ループを使用して の要素をトラバースするほうがはるかに優れていますArrayList。すべてが短くなります。

しかし、Java の作成者は再び私たちに砂糖を注ぐことにしました。私たちにとって幸運なことに、それは構文シュガーでした。

彼らは Java に新しい種類のループを与え、それをfor-eachループと呼びました。一般的には次のようになります。

for(Type name:collection)

ここでcollection、 はコレクション変数の名前、Typeはコレクション内の要素の型、 はnameループの各反復でコレクションから次の値を取得する変数の名前です。

この種のループは、暗黙的な反復子を使用してコレクションのすべての要素を反復処理します。実際の動作は次のとおりです。

For-each ループ コンパイラが認識する内容: イテレータを使用したループ
ArrayList<String> list = new ArrayList<String>();

for (String str: list)
{
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();
Iterator<String> it = list.iterator();

while (it.hasNext())
{
   String str = it.next();
   System.out.println(str);
}

コンパイラーはfor-eachコード内にループを検出すると、それを右側のコードに置き換えるだけです。欠落している他のメソッド呼び出しとともにイテレーターを取得するための呼び出しが追加されます。

プログラマはループを好みfor-each、コレクションのすべての要素を反復処理する必要がある場合は、ほとんどの場合ループを使用します。

ArrayListループを使用してリストを反復処理する場合でも、for-each短く見えます。

For-each ループ forループ
ArrayList<String> list = new ArrayList<String>();

for (String str: list)
{
   System.out.println(str);
}
ArrayList<String> list = new ArrayList<String>();

for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);
   System.out.println(str);
}


for-each4.ループ内の要素の削除

このfor-eachループには、要素を正しく削除できないという欠点が 1 つあります。このようなコードを書くとエラーが発生します。

コード ノート
ArrayList<String> list = new ArrayList<String>();

list.add("Hallo");
list.add("Hello");
list.add("Hola");
list.add("Bonjour");
list.add("Ciao");
list.add("Namaste");

for (String str: list)
{
   if (str.equals("Hello"))
      list.remove(str);
}












削除操作ではエラーが発生します。

これは非常に素晴らしくわかりやすいコードですが、機能しません。

重要!

イテレータによるコレクションのトラバース中にコレクションを変更することはできません。

この制限を回避するには 3 つの方法があります。

1. 別の種類のループを使用する

When traversing an ArrayList collection、カウンター変数を使用して通常のループを使用できますi

コード
for (int i = 0; i < list.size(); i++)
{
   String str = list.get(i);

   if (str.equals("Hello"))
   {
      list.remove(str);
      i--; // We need to decrease i, because the remove operation shifted the elements
   }
}

ただし、このオプションはコレクションには適していませHashSetHashMap

2. 明示的なイテレータを使用する

イテレータを明示的に使用して、そのremove()メソッドを呼び出すことができます。

動作するバージョン 動作しないバージョン
Iterator<String> it = set.iterator();
while (it.hasNext())
{
   String str = it.next();
   if (str.equals("Hello"))
       it.remove();
}

for (String str: list) { if (str.equals("Hello")) list.remove(str); }

remove()イテレータ オブジェクトでメソッドを呼び出していることに注意してください。イテレータは項目が削除されたことを認識しており、状況を正しく処理できます。

3. コレクションのコピーを使用する

コレクションのコピーを作成し、そのコピーをループ内で使用してfor-each、元のコレクションから要素を削除することもできます。

コード ノート
ArrayList<String> listCopy = new ArrayList(list);

for (String str: listCopy)
{
   if (str.equals("Hello"))
      list.remove(str);
}
コレクションのコピーの作成は非常に簡単です。



ループはコレクションのコピーに反復子を使用します。
要素がコレクションから削除されますlist

要素自体は複製されないため、コレクションはかなり早くコピーされます。代わりに、新しいコレクションには、古いコレクションにすでに存在する要素への参照が格納されます。