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

JavaのIteratorを使用すると、ListやMapなどのコレクションのループ処理が便利になります。

この記事では、Iteratorについて

  • Iterator(イテレータ)とは
  • Iteratorの使い方

ループ処理でListの要素を

  • 追加する方法
  • 削除する方法

など基本的な内容から、応用的な処理についても解説します。

今回はIteratorについて、くわしく解説していきます!

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メソッドの使い方についてもっとくわしく知りたい方は、こちらを参照してくださいね!

【Java入門】MapのkeySetの意味と使い方
更新日 : 2019年4月25日

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のさまざまな使い方については、以下の記事にまとめていますので、ぜひ参考にしてくださいね!

【Java入門】Mapの使い方総まとめ(HashMapで初期化、値のソート)
更新日 : 2019年5月22日

for文でのループ処理について知りたい方へ

今回の解説で使用したfor文でのループ処理についてくわしく知りたい方は、以下の記事にまとめていますので、ぜひ参考にしてくださいね!

【Java入門】for文、拡張for文、forEachの使い方
更新日 : 2019年6月25日

while文でのループ処理について知りたい方へ

今回の解説で使用したwhile文でのループ処理についてくわしく知りたい方は、以下の記事にまとめていますので、ぜひ参考にしてくださいね!

【3分でわかるJava】while文とdo-while文の使い方
更新日 : 2018年10月25日

まとめ

ここでは、Iteratorを使用した基本的なループ処理や、値の追加や削除の方法、削除時の危険性など説明しました。ListやMapなどの値をループで処理する場合は、Iteratorを使用したほうが、正確に処理をすることが可能です。

もし、Iteratorの使い方を忘れてしまったら、この記事を思い出してくださいね。

LINEで送る
Pocket

SEからWebエンジニアへ転職した理由

侍エンジニア塾卒業生の小池さんは、以前は社内SEとして約5年ほど勤務していました。しかし業務内容は社内のヘルプデスク対応など、プログラムを書く仕事は全くなかったそうです。

SEながらプログラムを書けない現状に「将来仕事がなくなるんじゃないか」と不安を感じ、プログラミング学習を決意。

弊社スクールで学習し、無事ベンチャー企業のプログラマーとして転職に成功しました。そんな小池さんの学習法や転職体験談を伺いましたので、是非ご覧ください。

「プログラミングができないSEは仕事がなくなる」不安を感じたSEが未経験から転職成功するまで
更新日 : 2019年10月7日

書いた人

ヤマシタ

エンジニア歴10年のフリーランスエンジニア。ITに関わるさまざまなコンテンツの企画・制作も行っています。
ITに関してはノウハウ系、ライフハック系、トレンド系など、200本以上の執筆経験があります。

おすすめコンテンツ

あなたにぴったりなプログラミング学習プランを無料で診断!

プログラミング学習の効率を劇的に上げる学習メソッドを解説