iterating over and removing from a map [duplicate]

2019-01-01 14:20发布

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

标签: java
12条回答
弹指情弦暗扣
2楼-- · 2019-01-01 14:59

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.

查看更多
初与友歌
3楼-- · 2019-01-01 15:02

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.

查看更多
萌妹纸的霸气范
4楼-- · 2019-01-01 15:02

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
查看更多
余生无你
5楼-- · 2019-01-01 15:04

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

查看更多
人气声优
6楼-- · 2019-01-01 15:05

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);
}
查看更多
荒废的爱情
7楼-- · 2019-01-01 15:06

As of Java 1.8 you could do this using with:

map.entrySet().removeIf(e-> <boolean expression> );
查看更多
登录 后发表回答