iterating over and removing from a map [duplicate]
I was doing:
for (Object key : map.keySet())
if (something)
map.remove(key);
which threw a ConcurrentModificationException, so i changed it to:
for (Object key : new ArrayList<Object>(map.keySet()))
if (something)
map.remove(key);
this, and any other procedures that modify the map are in synchronized blocks.
is there a better solution?
Solution 1:
Here is a code sample to use the iterator in a for loop to remove the entry.
Map<String, String> map = new HashMap<String, String>() {
{
put("test", "test123");
put("test2", "test456");
}
};
for(Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); it.hasNext(); ) {
Map.Entry<String, String> entry = it.next();
if(entry.getKey().equals("test")) {
it.remove();
}
}
Solution 2:
As of Java 8 you could do this as follows:
map.entrySet().removeIf(e -> <boolean expression>);
Oracle Docs: entrySet()
The set is backed by the map, so changes to the map are reflected in the set, and vice-versa
Solution 3:
Use a real iterator.
Iterator<Object> it = map.keySet().iterator();
while (it.hasNext())
{
it.next();
if (something)
it.remove();
}
Actually, you might need to iterate over the entrySet()
instead of the keySet()
to make that work.
Solution 4:
is there a better solution?
Well, there is, definitely, a better way to do so in a single statement, but that depends on the condition based on which elements are removed.
For eg: remove all those elements where value
is test, then use below:
map.values().removeAll(Collections.singleton("test"));
UPDATE It can be done in a single line using Lambda expression in Java 8.
map.entrySet().removeIf(e-> <boolean expression> );
I know this question is way too old, but there isn't any harm in updating the better way to do the things :)
Solution 5:
ConcurrentHashMap
You can use java.util.concurrent.ConcurrentHashMap
.
It implements ConcurrentMap
(which extends the Map
interface).
E.g.:
Map<Object, Content> map = new ConcurrentHashMap<Object, Content>();
for (Object key : map.keySet()) {
if (something) {
map.remove(key);
}
}
This approach leaves your code untouched. Only the map
type differs.