JavaのIteratorを使用すると、ListやMapなどのコレクションのループ処理が便利になります。
この記事では、Iteratorについて
- Iterator(イテレータ)とは
- Iteratorの使い方
ループ処理でListの要素を
- 追加する方法
- 削除する方法
など基本的な内容から、応用的な処理についても解説します。
今回はIteratorについて、くわしく解説していきます!
なお、Javaの記事については、こちらにまとめています。
Iterator(イテレータ)とは
Iteratorインタフェースは、ListやMapなどのコレクションの要素を、順番に処理する場合に使用します。
Iteratorは、次の要素数がある場合にtrueを返すhasNextメソッドや、次の要素を取得する場合に用いるnextメソッドを用いて、使用します。
ループ処理でMapの要素を操作する方法
ここでは、Iteratorを使ってMapの要素を取得する方法について解説します。
IteratorでMapのkeyを取得する方法
Iteratorを使ってMapのkeyを取得することができます。
サンプルコードで確認していきましょう。
import java.util.Map; import java.util.HashMap; import java.util.Iterator; public class Main { public static void main(String[] args) { // Mapの宣言 Map<String, Integer> map = new HashMap<String, Integer>(); // Mapに要素を追加 map.put("apple", 100); map.put("orange", 200); map.put("melon", 300); // Iterator<String> の宣言 Iterator<String> key_itr = map.keySet().iterator(); // hasNextを使用して値がある場合はループを継続する // keyの取得 while(key_itr.hasNext()) { // nextを使用して値を取得する String str = (String)key_itr.next(); System.out.println(str); } } }
実行結果:
orange apple melon
このサンプルコードでは、まずHashMapクラスを使って変数mapを宣言し、mapに要素を追加します。
次にIteratorインタフェースのkey_itrを宣言し、keySetメソッドを使ってmapのkey値を取得しています。hasNextメソッドを使用し、次の要素がある場合はtrueを返し、whileによるループを継続させます。nextメソッドを使用し、mapのkeyを取得しています。
なお、HashMapで追加された値は順不同となります。keySetメソッドの使い方についてもっとくわしく知りたい方は、こちらを参照してくださいね!
IteratorでMapのvalueを取得する方法
Iteratorを使ってMapのvalue値も取得することができます。
サンプルコードで確認していきましょう。
import java.util.Map; import java.util.HashMap; import java.util.Iterator; public class Main { public static void main(String[] args) { // Mapの宣言 Map<String, Integer> map = new HashMap<String, Integer>(); // Mapに要素を追加 map.put("apple", 100); map.put("orange", 200); map.put("melon", 300); // Iterator<Integer> の宣言 Iterator<Integer> val_itr = map.values().iterator(); // valueの取得 while(val_itr.hasNext()) { // nextを使用して値を取得する Integer i = (Integer)val_itr.next(); System.out.println(i); } } }
実行結果:
200 100 300
このサンプルコードでは、同じようにしてIteratorインタフェースのval_itrを宣言し、valuesメソッドを使ってmapのvalue値を取得しています。
IteratorでMapのkey、valueをセットで取得する方法
Iteratorを使ってMapのkey、valueをセットで取得することができます。
サンプルコードで確認していきましょう。
import java.util.Map; import java.util.HashMap; import java.util.Iterator; public class Main { public static void main(String[] args) { // Mapの宣言 Map<String, Integer> map = new HashMap<String, Integer>(); // Mapに要素を追加 map.put("apple", 100); map.put("orange", 200); map.put("melon", 300); // Iterator<Map.Entry<String, Integer>> の宣言 Iterator<Map.Entry<String, Integer>> itr = map.entrySet().iterator(); // key, valueの取得 while(itr.hasNext()) { // nextを使用して値を取得する Map.Entry<String, Integer> entry = itr.next(); System.out.println(entry.getKey() + " : " + entry.getValue()); } } }
実行結果:
orange : 200 apple : 100 melon : 300
このサンプルコードでは、Iteratorインタフェースのitrを宣言し、entrySetメソッドを使ってmapのkey値とvalue値をセットで取得しています。
ループ処理でListの要素を操作する方法
先ほどはIteratorでMapの要素を取得する方法について解説しました。
ここでは、Iteratorを使用してListの要素を順番に取得する処理を解説します。また、Iteratorの応用編として、ListIteratorを使用して値を追加する方法、ループの中で値を削除する方法を詳しく解説していきます!
IteratorでListの要素を取得する方法
ここでは、実際にArrayListクラスで宣言したlistに要素を追加し、Iteratorを使用してlistの要素を順番に取得する処理を解説します。
以下にIteratorの基本的な使い方を記述します。
import java.util.ArrayList; import java.util.Iterator; public class Main { public static void main(String[] args) { // Listの宣言 ArrayList<String> list = new ArrayList<String>(); // Listに要素を追加 list.add("apple"); list.add("orange"); list.add("melon"); // Iterator<String> の宣言 Iterator<String> itr = list.iterator(); // hasNextを使用して値がある場合はループを継続する while(itr.hasNext()) { // nextを使用して要素を取得する String str = (String)itr.next(); System.out.println(str); } } }
実行結果:
apple orange melon
このサンプルコードでは、まずArrayListクラスを宣言し、変数listに要素を追加します。次にIteratorインタフェースのitrを宣言し、listの全要素を取得しています。
ListIteratorで要素を追加する方法
Iteratorでループ中に値を追加したい場合、ListIteratorインタフェースを使用します。以下にループ中に値を追加する方法を記述します。
import java.util.ArrayList; import java.util.Iterator; import java.util.ListIterator; public class Main { public static void main(String[] args) { // Listの宣言 ArrayList<Integer> list = new ArrayList<Integer>(); // Listに値を追加 list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); // ListIterator<Integer>の宣言 ListIterator<Integer> itr = list.listIterator(); while(itr.hasNext()) { Integer num1 = itr.next(); if (num1 == 5) { itr.add(6); } } System.out.println(list); } }
実行結果:
[1, 2, 3, 4, 5, 6]
このサンプルコードでは、まずArrayListクラスを宣言し、変数listに値を追加します。
次にListIteratorインタフェースのitrを宣言し、listの全要素を取得します。Iteratorでのループ中に値が5の場合はaddメソッドを使用して、値を追加しています。
ArrayListの中身を確認すると、6が追加されているのがわかります。
ループ処理で要素を削除する方法
MapやListなどのコレクションをループの中で削除するためには、removeメソッドを使用します。
Iteratorでのループを使用せずに、for文などで要素数分ループして値を削除することも可能ですが、Iteratorメソッドを使用しないと、非効率になったり思わぬ問題が発生する場合があります。
for文で要素数分ループする場合
まずは、以下のようにIteratorメソッドを使用しないで、for文で削除する方法を記述します。
import java.util.ArrayList; public class Main { public static void main(String[] args) { // Listの宣言 ArrayList<Integer> list = new ArrayList<Integer>(); // Listに値を追加 list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); // Listのサイズ分ループする for(int i=0; i<list.size(); i++) { // 値が1または4の場合はリストを削除 if (i == 1 || i == 4) { list.remove(i); } } System.out.println("list = " + list); } }
実行結果:
list = [1, 3, 4, 5]
このサンプルコードでは、listを要素数分ループし、値が1または4の場合はremoveメソッドを使用して、値を削除しています。
しかし、実行結果を見る限りでは、実際に削除されている要素は2のみとなっています。
これは、removeメソッドで削除時にi番目(ここでは1番目)を指定していますが、コレクション型は要素数が0から始まるため、実際には2番目の値が削除されてしまいます。
また、listを削除するごとに要素数が1つ減ってしまいます。(0、1、2、3となる)そのため、「i == 4」に到達するこはなく、listの中身を確認すると、要素数2のみが削除された形となってしまいます。
また、sizeメソッドをループ毎に呼び出していますが、メソッドを呼ぶこと自体わずかながら負荷がかかってしまいます。sizeメソッドを使用してのループ処理は、システムの負荷が高まって、予期しない問題が発生する危険性もあります。
とくに膨大なデータ量(何万〜何十万)がある場合は、推奨できません。
for文で保存した要素数分ループする場合
そこで、変数にlistのサイズを保存しておいて、その変数を使うことでメソッドの呼び出し回数を減らしながら、listの要素数分ループ処理をさせるという方法もあります。
以下にサイズを指定してループの中でlistの値を削除するサンプルを記述します。
import java.util.ArrayList; public class Main { public static void main(String[] args) { // Listの宣言 ArrayList<Integer> list = new ArrayList<Integer>(); // Listに値を追加 list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); // 毎回sizeメソッドを呼ぶのはシステムの負荷が高まるため、 // 一旦、int型の変数にListのサイズを保存する int size = list.size(); // Listのサイズ分ループする for(int i=0; i<size; i++) { // 値が1または4の場合はリストを削除 if (i == 1 || i == 4) { list.remove(i); } } System.out.println("list = " + list); } }
このサンプルコードを実行すると、”java.lang.IndexOutOfBoundsException”の例外が発生します。
リストのサイズを事前に取得し、リストのサイズ分ループしていますが、ループの中でlistの値を削除した結果、listのサイズの値も減ってしまいます。
そのため、変数sizeで取得したサイズ数分の要素が参照できずに、例外が発生してしまいます。
拡張for文を使う場合
では、拡張for文を使って削除するとどうなるのか?
拡張for文に置き換えてみます。
import java.util.ArrayList; public class Main { public static void main(String[] args) { // Listの宣言 ArrayList<Integer> list = new ArrayList<Integer>(); // Listに値を追加 list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); // 拡張for文 for(Integer i : list) { if (i == 3) { list.remove(i); } } System.out.println("list = " + list); } }
このサンプルコードを実行すると、”java.util.ConcurrentModificationException”の例外が発生します。
これは、ループの中でCollectionの値が変更されると、例外が投げられるためです。
Iteratorでのループ中に要素を削除する場合
for文や拡張for文が発生すると、思わぬ問題や例外が発生することがわかりました。そのため、正確にListの値を削除するためには、Iteratorを使用します。
以下にIteratorでのループ中に値を削除する方法を記述します。
import java.util.ArrayList; import java.util.Iterator; public class Main { public static void main(String[] args) { // Listの宣言 ArrayList<Integer> list = new ArrayList<Integer>(); // Listに値を追加 list.add(1); list.add(2); list.add(3); list.add(4); list.add(5); // Iterator<Integer> の宣言 Iterator<Integer> itr = list.iterator(); // hasNextを使用して値がある場合はループを継続する while(itr.hasNext()) { // nextを使用して値を取得する Integer num2 = itr.next(); // 値が3の場合 if (num2 == 3) { // 値を削除する itr.remove(); } } System.out.println("list = " + list); } }
実行結果:
list = [1, 2, 4, 5]
Iteratorでのループ中に値が3の場合は、removeメソッドを使用して値を削除しています。ArrayListの中身を確認すると、意図したとおり3が削除されているのがわかります。
Mapについてもっと詳しく知りたい方へ
Mapのさまざまな使い方については、以下の記事にまとめていますので、ぜひ参考にしてくださいね!
for文でのループ処理について知りたい方へ
今回の解説で使用したfor文でのループ処理についてくわしく知りたい方は、以下の記事にまとめていますので、ぜひ参考にしてくださいね!
while文でのループ処理について知りたい方へ
今回の解説で使用したwhile文でのループ処理についてくわしく知りたい方は、以下の記事にまとめていますので、ぜひ参考にしてくださいね!
まとめ
ここでは、Iteratorを使用した基本的なループ処理や、値の追加や削除の方法、削除時の危険性など説明しました。ListやMapなどの値をループで処理する場合は、Iteratorを使用したほうが、正確に処理をすることが可能です。
もし、Iteratorの使い方を忘れてしまったら、この記事を思い出してくださいね。