tags:

views:

211

answers:

7

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?

if no one comes up with a better solution, first to say no gets the tick ;)

+10  A: 

Use a real iterator.

Iterator<Object> it = map.keySet().iterator();

while (it.hasNext())
  if (something)
    it.remove();

Actually, you might need to iterator over the entrySet() instead of the keySet() to make that work.

Paul Tomblin
This does seem a bit more elegant than my solution of iterating over the entry set. Its not very obvious though that removing from the key set removes things from the map (i.e. the key set can be a copy)
Gennadiy
Sorry to double comment. I have confirmed that removing from the key set indeed removes from the map, although not as obvious as removing from the entry set.
Gennadiy
Iterating over the key set is the way to do it.
Tom Hawtin - tackline
(Although to match the question, it should be `Iterator<Integer>`.)
Tom Hawtin - tackline
Tom, in the first loop he's using "for (Object key:", so that's why I used an Object iterator.
Paul Tomblin
+1  A: 

You have to use Iterator to safely remove element while traversing a map.

Alexander Pogrebnyak
+5  A: 

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();
      }
    }
Gennadiy
A: 

Maybe you can iterate over the map looking for the keys to remove and storing them in a separate collection. Then remove the collection of keys from the map. Modifying the map while iterating is usually frowned upon. This idea may be suspect if the map is very large.

Vincent Ramdhanie
A: 

If this method and the other method that modify the map are in synchronized blocks, I don't see why you have to do anything? Maybe I'm not understanding your question completely? Can ou please post the rest of the code?

Amir Afghani
Ah, I didn't notice that you weren't calling the iterator routine on keySet!
Amir Afghani
A: 

An alternative, more verbose way

List<SomeObject> toRemove = new ArrayList<SomeObject>();
for (SomeObject key: map.keySet()) {
    if (something) {
        toRemove.add(key);
    }
}

for (SomeObject key: toRemove) {
    map.remove(key);
}
vickirk
A: 

I agree with Paul Tomblin. I usually use the keyset's iterator, and then base my condition off the value for that key:

Iterator<Integer> it = map.keySet().iterator();
while(it.hasNext()) {
    Integer key = it.next();
    Object val = map.get(key);
    if (val.shouldBeRemoved()) {
        it.remove();
    }
}
goatlinks