迭代并从地图中删除

pst*_*ton 243 java

我在做:

for (Object key : map.keySet())
    if (something)
        map.remove(key);
Run Code Online (Sandbox Code Playgroud)

它引发了一个ConcurrentModificationException,所以我将其更改为:

for (Object key : new ArrayList<Object>(map.keySet()))
    if (something)
        map.remove(key);
Run Code Online (Sandbox Code Playgroud)

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

有更好的解决方案吗?

如果没有人想出一个更好的解决方案,首先要说没有得到勾号;)

Gen*_*diy 374

下面是一个代码示例,它在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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 所以,你在循环中执行:`it.remove()`而不是`collection.remove(key)`.这很棒! (16认同)
  • 这个答案适用于Java 8之前的代码,但如果您使用Java 8,elron的答案更可取.http://stackoverflow.com/a/29187813/2077574 (11认同)

noe*_*ego 240

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

map.entrySet().removeIf(e -> <boolean expression>);
Run Code Online (Sandbox Code Playgroud)

  • 请注意,“map.values()”和“map.keySet()”也支持“removeIf()”。 (9认同)
  • map.values() 上的removeIf 的行为是什么?它删除了所有指向该值的 key-&gt;val 元素? (2认同)

Pau*_*lin 98

使用真正的迭代器.

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

while (it.hasNext())
{
  it.next();
  if (something)
    it.remove();
 }
Run Code Online (Sandbox Code Playgroud)

实际上,您可能需要迭代entrySet()而不是keySet()使其工作.

  • 抱歉双重评论.我已经确认从键集中删除确实从映射中删除了,尽管不像从条目集中删除那么明显. (8认同)
  • `Iterator.next()`或者在这种情况下`it.next()`必须在调用`remove`之前调用,否则会出现`IllegalStateException`. (7认同)
  • 对于记录,这也适用于映射值:`Iterator it = map.values().iterator()`,然后`it.remove()`将删除它的条目. (7认同)
  • 这似乎比我在迭代条目集上的解决方案更优雅.虽然从密钥集中删除会从地图中删除内容(即密钥集可以是副本)但不是很明显 (3认同)

Shi*_*mar 46

有更好的解决方案吗?

嗯,肯定有一种更好的方法可以在一个语句中这样做,但这取决于基于哪些元素被删除的条件.

为例如:其中删除所有这些元素value测试,然后使用以下:

map.values().removeAll(Collections.singleton("test"));
Run Code Online (Sandbox Code Playgroud)

更新 可以使用Java 8中的Lambda表达式在一行中完成.

map.entrySet().removeIf(e-> <boolean expression> );
Run Code Online (Sandbox Code Playgroud)

我知道这个问题太老了,但更新更好的方法来做事情没有任何伤害:)

  • 要删除哪个键是test的元素:map.keySet().removeAll(Collections.singleton("test")); (2认同)

ROM*_*eer 22

的ConcurrentHashMap

你可以用java.util.concurrent.ConcurrentHashMap.

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

例如:

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

for (Object key : map.keySet()) {
    if (something) {
        map.remove(key);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这种方法的问题是ConcurrentHashMap不允许"null"作为值(或键),因此如果您正在处理包含null的映射,则无法使用此方法. (9认同)

小智 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 ); 
    });
}
Run Code Online (Sandbox Code Playgroud)

结果如下:

Key: 1   Value: one
Key: 2   Value: two
Key: 3   Value: three
After removing element
Key: 1   Value: one
Key: 2   Value: two
Run Code Online (Sandbox Code Playgroud)


Ale*_*yak 5

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