iterating over and removing from a map [duplicate]

2019-01-01 14:45发布

问题:

This question already has an answer here:

  • Iterating through a Collection, avoiding ConcurrentModificationException when removing objects in a loop 23 answers

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 ;)

回答1:

As of Java 1.8 you could do this using with:

map.entrySet().removeIf(e-> <boolean expression> );


回答2:

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


回答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.



回答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 :)



回答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.



回答6:

Java 8 support a more declarative approach to iteration, in that we specify the result we want rather than how to compute it. Benefits of the new approach are that it can be more readable, less error prone.

public static void mapRemove() {

    Map<Integer, String> map = new HashMap<Integer, String>() {
        {
            put(1, \"one\");
            put(2, \"two\");
            put(3, \"three\");
        }
    };

    map.forEach( (key, value) -> { 
        System.out.println( \"Key: \" + key + \"\\t\" + \" Value: \" + value );  
    }); 

    map.keySet().removeIf(e->(e>2)); // <-- remove here

    System.out.println(\"After removing element\");

    map.forEach( (key, value) -> { 
        System.out.println( \"Key: \" + key + \"\\t\" + \" Value: \" + value ); 
    });
}

And result is as follows:

Key: 1   Value: one
Key: 2   Value: two
Key: 3   Value: three
After removing element
Key: 1   Value: one
Key: 2   Value: two


回答7:

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



回答8:

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


回答9:

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);
}


回答10:

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.



回答11:

And this should work as well..

ConcurrentMap<Integer, String> running = ... create and populate map

Set<Entry<Integer, String>> set = running.entrySet();    

for (Entry<Integer, String> entry : set)
{ 
  if (entry.getKey()>600000)
  {
    set.remove(entry);    
  }
}


回答12:

Set s=map.entrySet();
Iterator iter = s.iterator();

while (iter.hasNext()) {
    Map.Entry entry =(Map.Entry)iter.next();

    if(\"value you need to remove\".equals(entry.getKey())) {
         map.remove();
    }
}


标签: java