Java - 繰り返しステートメント内のHashMap要素を削除する

for、whileなど、反復文の中でHashMapを巡回しながら要素を削除する方法を紹介します。

1. ConcurrentModificationException

繰り返し文を使用して HashMap を巡回しながら、特定の条件の要素を削除する場合があります。

問題は、 HashMap 巡回中、要素を削除すると ConcurrentModificationException が発生することがあります。

たとえば、以下のように HashMap を巡回しながら HashMap.remove() で要素を削除すると Exception が発生することがあります。 したがって、以下のように削除しないでください。

import java.util.HashMap;

public class Example {

    public static void main(String[] args) {

        HashMap<String, Integer> map = new HashMap<>();
        map.put("apple", 100);
        map.put("kiwi", 200);
        map.put("banana", 300);
        map.put("grape", 400);

        for (String key: map.keySet()) {
            if (key.startsWith("k")) {
                map.remove(key);
            }
        }

        System.out.println(map);
    }
}

Output:

Exception in thread "main" java.util.ConcurrentModificationException
	at java.base/java.util.HashMap$HashIterator.nextNode(HashMap.java:1597)
	at java.base/java.util.HashMap$KeyIterator.next(HashMap.java:1620)
	at Example.main(Example.java:13)

2. Iteratorで巡回中の要素を削除する

Iterator を使って巡回しながら Iterator.remove() で要素を削除することは Exception が発生しません。

以下のように特定の要素を削除するように実装できます。

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class Example {

    public static void main(String[] args) {

        HashMap<String, Integer> map = new HashMap<>();
        map.put("apple", 100);
        map.put("kiwi", 200);
        map.put("banana", 300);
        map.put("grape", 400);

        Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator();
        while (it.hasNext()) {
            if (it.next().getKey().startsWith("k")){
                it.remove();
            }
        }

        System.out.println(map);
    }
}

Output:

{banana=300, apple=100, grape=400}

3. Listを使用してHashMap要素を削除する

HashMap 巡回中に削除する要素をリストに保存し、List を再度巡回しながら HashMap の要素を削除できます。 HashMap 巡回中の要素を削除するものではないため、ConcurrentModificationException は発生しません。

以下のように要素を削除できます。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class Example {

    public static void main(String[] args) {

        HashMap<String, Integer> map = new HashMap<>();
        map.put("apple", 100);
        map.put("kiwi", 200);
        map.put("banana", 300);
        map.put("grape", 400);

        List<String> willRemove = new ArrayList<>();
        for (String key: map.keySet()) {
            if (key.startsWith("k")) {
                willRemove.add(key);
            }
        }

        for (String str : willRemove) {
            map.remove(str);
        }
        System.out.println(map);
    }
}

Output:

{banana=300, apple=100, grape=400}

4. removeIf() で巡回中の要素を削除する

removeIf() は引数として 1 つの引数と戻り値を持つ関数型インタフェースを受け取ります。この関数である要素に対して true を返すと、その要素は削除されます。

removeIf() も ConcurrentModificationException を発生させないので、この方法で要素を削除できます。

以下のように特定の要素を削除するように実装できます。

import java.util.HashMap;

public class Example {

    public static void main(String[] args) {

        HashMap<String, Integer> map = new HashMap<>();
        map.put("apple", 100);
        map.put("kiwi", 200);
        map.put("banana", 300);
        map.put("grape", 400);

        map.entrySet().removeIf(entry -> entry.getKey().startsWith("k"));

        System.out.println(map);
    }
}

Output:

{banana=300, apple=100, grape=400}

4.1 HashMap.keySet().removeIf()

entrySet()の代わりにkeySet()を使って要素を削除することもできます。

keySet() は HashMap のすべての key に対する collection なので、 key だけを巡回できます。

import java.util.HashMap;

public class Example {

    public static void main(String[] args) {

        HashMap<String, Integer> map = new HashMap<>();
        map.put("apple", 100);
        map.put("kiwi", 200);
        map.put("banana", 300);
        map.put("grape", 400);

        map.keySet().removeIf(key -> key.startsWith("k"));

        System.out.println(map);
    }
}

Output:

{banana=300, apple=100, grape=400}

4.2 HashMap.values().removeIf()

values() は HashMap の value を collection として返し、 removeIf() で特定の value の要素を削除できます。

import java.util.HashMap;

public class Example {

    public static void main(String[] args) {

        HashMap<String, Integer> map = new HashMap<>();
        map.put("apple", 100);
        map.put("kiwi", 200);
        map.put("banana", 300);
        map.put("grape", 400);

        map.values().removeIf(val -> val == 200);

        System.out.println(map);
    }
}

Output:

{banana=300, apple=100, grape=400}
codechachaCopyright ©2019 codechacha