Explain Codes LogoExplain Codes Logo

Iterating over and removing from a map

java
concurrentmodificationexception
lambda-expressions
map-modification
Nikita BarsukovbyNikita Barsukov·Oct 31, 2024
TLDR

Iterate and remove entries from a Map, safely with an Iterator. Use Iterator.remove() during traversal with map.entrySet().iterator(), it's the best way to avoid ConcurrentModificationException.

Map<String, Integer> map = new HashMap<>(); map.put("a", 1); map.put("b", 2); Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator(); while (it.hasNext()) { //I'm on a diet, no values more than 1 for me, please. if (it.next().getValue() < 2) it.remove(); }

Replace the comparison in the if statement with your removal condition.

Mastering Java 8

Making your life easier with removeIf

Java 8 brought us the great removeIf method in Map. Simple, expressive and ConcurrentModificationException-proof.

map.entrySet().removeIf(entry -> entry.getValue() < 2);

With this, you can forget about handling the iterator manually. Isn't life beautiful?

Taming the concurrency beast

For thrill-seekers dealing with multithreading, ConcurrentHashMap or synchronizing your map modifications is a must:

ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>(); concurrentMap.putAll(map); //Look Ma, no locks! concurrentMap.keySet().removeIf(key -> concurrentMap.get(key) < 2);

This ensures no threads crash the party while you're modifying your map.

Keeping it safe with collection views

values().removeAll or generating a new ArrayList from keySet() gives you habour in the stormy sea of ConcurrentModificationException:

map.values().removeAll(Collections.singleton(valueToRemove));

This trick mirrors changes on both sides without having to deal with possible exceptions.

Embracing Lambda expressions and avoiding pitfalls

Lambda to the rescue!

Java 8's sexy Stream API can turn your complex removal conditions into an opera of readability:

map.keySet().removeIf(key -> someComplicatedCondition(key));

Just replace someComplicatedCondition(key) with your own spicy boolean condition.

A word of caution

Remember kids, always use protection! In this case Iterator.remove(). Never manipulate the map directly, else you might catch ConcurrentModificationException.

The Swiss army knife of map modification

Removing specific values

Got a grudge against a specific value? Wipe it away with values().removeAll and Collections.singleton!

map.values().removeAll(Collections.singleton(valueToRemove));

With this you become the Thanos of your Map, snapping away any specific undesired value.

Multi-threading considerations

In multithreaded environments, use synchronized blocks if working on a non-concurrent collection. It's like those "Do Not Disturb" hotel room signs:

synchronized (map) { Iterator<Map.Entry<String, Integer>> iterator = map.entrySet().iterator(); while (iterator.hasNext()) { // Gym rat mentality:¬ Nothing over '1'! if (iterator.next().getValue() < 2) iterator.remove(); } }

This is your VIP pass to make the map exclusively yours during iteration and modification.