迭代并从地图中删除

时间:2009-12-10 23:36:24

标签: java

我在做:

for (Object key : map.keySet())
    if (something)
        map.remove(key);

引发了ConcurrentModificationException,因此我将其更改为:

for (Object key : new ArrayList<Object>(map.keySet()))
    if (something)
        map.remove(key);

这个,以及修改地图的任何其他过程都在同步块中。

有更好的解决方案吗?

如果没有人提出更好的解决方案,首先要说不得嘀嗒;)

12 个答案:

答案 0 :(得分:364)

以下是在for循环中使用迭代器删除条目的代码示例。

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

答案 1 :(得分:210)

从Java 8开始,您可以按照以下方式执行此操作:

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

答案 2 :(得分:95)

使用真正的迭代器。

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

while (it.hasNext())
{
  it.next();
  if (something)
    it.remove();
 }

实际上,您可能需要迭代entrySet()而不是keySet()才能使其发挥作用。

答案 3 :(得分:43)

  

有更好的解决方案吗?

嗯,肯定有一种更好的方式在单一陈述中这样做,但这取决于基于哪些元素被移除的条件。

例如:删除所有value test 的元素,然后使用以下内容:

map.values().removeAll(Collections.singleton("test"));

<强>更新 它可以使用Java 8中的Lambda表达式在一行中完成。

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

我知道这个问题已经过时了,但是更新更好的做事方式没有任何损害:)

答案 4 :(得分:22)

<强>的ConcurrentHashMap

您可以使用java.util.concurrent.ConcurrentHashMap

它实现了ConcurrentMap(扩展了Map接口)。

<强> E.g

Map<Object, Content> map = new ConcurrentHashMap<Object, Content>();

for (Object key : map.keySet()) {
    if (something) {
        map.remove(key);
    }
}

这种方法使您的代码不受影响。只有map类型不同。

答案 5 :(得分:7)

Java 8支持更具声明性的迭代方法,因为我们指定了我们想要的结果而不是如何计算它。新方法的好处是它可以更易读,更不容易出错。

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

结果如下:

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

答案 6 :(得分:5)

在遍历地图时,您必须使用Iterator安全地删除元素。

答案 7 :(得分:3)

我同意保罗·汤姆林的观点。我通常使用键集的迭代器,然后将我的条件基于该键的值:

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

答案 8 :(得分:2)

另一种更详细的方式

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

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

答案 9 :(得分:1)

也许您可以遍历地图,查找要删除的密钥并将其存储在单独的集合中。然后从地图中删除键集合。迭代时修改地图通常是不受欢迎的。如果地图非常大,这个想法可能会被怀疑。

答案 10 :(得分:1)

这也应该有用..

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

答案 11 :(得分:-1)

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