【问题标题】:java : why is it safe to modify a map's entry's value while we are iterating over it?java : 为什么在我们迭代它时修改映射条目的值是安全的?
【发布时间】:2012-08-09 22:26:16
【问题描述】:

假设一个映射包含整数键和一个字符串列表作为它的值。然后,我不能这样做:

for (Map.Entry<Integer, List<String>> entry : map.entrySet()){
    for (String string : entry.getValue()){
        if (string.startsWith("a")){
           entry.getValue().remove(string);
        }
    }
}

它抛出ConcurrentModificationException。但如果我执行以下操作:

for (Map.Entry<Integer, List<String>> entry : map.entrySet()){
    entry.setValue(new ArrayList<String>());
}

这非常有效。我们现在不是在修改底层地图吗?

【问题讨论】:

  • 我们正在更改值而不是添加或删除任何新条目,因此键集保持不变。
  • 顺便说一句,如果您使用Iterator.remove(),第一个示例不会抛出 CME
  • 如果我更改值 Object 的任何属性。例如,如果值是 List 并且我在迭代时更改了雇员对象的名称,为什么在这种情况下它会引发并发修改,因为我们没有更改这种情况下的键

标签: java concurrency map loops


【解决方案1】:

请查看 HashMap.java 中 entrySet() 的 Javadoc,您会发现原因!

来自the documentation

返回此映射中包含的映射的 Set 视图。集合由地图支持,因此对地图的更改会反映在集合中,反之亦然。如果在对集合进行迭代时修改了映射(通过迭代器自己的删除操作或通过迭代器返回的映射条目上的 setValue 操作除外),则迭代的结果是未定义的。该集合支持元素移除,即通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作从映射中移除相应的映射。它不支持 add 或 addAll 操作。

指定者:Map中的entrySet(),

覆盖:AbstractMap 中的 entrySet()

返回:此地图中包含的映射的集合视图

【讨论】:

    【解决方案2】:

    问题与Map 无关,仅与您使用值列表的方式有关。以下任何ArrayList 都会失败:

    for (String string : list){
        if (string.startsWith("a")){
           list.remove(string);
        }
    }
    

    原因在ArrayList的Javadoc中讨论过:

    此类的 iterator 和 listIterator 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时候对列表进行结构修改,除了通过迭代器自己的 remove 或 add 方法之外的任何方式,迭代器将抛出并发修改异常。因此,面对并发修改,迭代器会快速而干净地失败,而不是在未来不确定的时间冒任意的、非确定性的行为。

    (换句话说:如果你从列表中删除元素,迭代器可能不再指向底层数组中的正确索引。因此,它不允许你使用可能损坏的迭代器,而是抛出一个ConcurrentModificationException 礼貌地让你知道你需要重新设计你的程序。)

    一个简单的解决方法是使用

    Iterator<String> itr = entry.getValue().iterator();
    while (itr.hasNext()) {
      if (itr.next().startsWith("a")) {
        itr.remove();
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-07-08
      • 2011-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-26
      • 2010-10-15
      • 2020-12-20
      • 2023-03-15
      相关资源
      最近更新 更多