【解決Java】Mapのループ処理でIteratorを使う方法

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の使い方を忘れてしまったら、この記事を思い出してくださいね。

この記事を書いた人

【プロフィール】
DX認定取得事業者に選定されている株式会社SAMURAIのマーケティング・コミュニケーション部が運営。「質の高いIT教育を、すべての人に」をミッションに、IT・プログラミングを学び始めた初学者の方に向け記事を執筆。
累計指導者数4万5,000名以上のプログラミングスクール「侍エンジニア」、累計登録者数1万8,000人以上のオンライン学習サービス「侍テラコヤ」で扱う教材開発のノウハウ、2013年の創業から運営で得た知見に基づき、記事の執筆だけでなく編集・監修も担当しています。
【専門分野】
IT/Web開発/AI・ロボット開発/インフラ開発/ゲーム開発/AI/Webデザイン

目次