假设我正在迭代Java中的Map ...我不清楚在迭代过程中我能对Map进行什么操作。我想我对Javadoc中用于Iterator接口删除方法的警告感到困惑:
[...]如果在迭代进行过程中以除调用此方法之外的任何方式修改基础集合,则未指定迭代器的行为。
我确信我可以毫无问题地调用remove方法。但是在迭代Map集合时,我可以:
使用Map类put方法更改与键关联的值(使用现有键放置)?
使用Map类put方法添加一个新条目(使用新密钥放置)?
使用Map类删除方法删除条目?
我的猜测是我可以放心地做#1(放到现有的钥匙上),但不能安全地做#2或#3。
提前感谢您对此的任何澄清。
答案 0 :(得分:13)
您可以使用Iterator.remove()
,如果使用(Map.Entry)的entrySet迭代器,您可以使用Map.Entry.setValue()
。任何其他和所有的赌注都是关闭的 - 你不应该直接改变地图,有些地图会
不允许上述任何一种或两种方法。
具体而言,您的(1),(2)和(3)不允许。
您可能会通过Map
对象设置现有密钥的值,但Set.iterator()
文档明确排除了这一点,它将是特定于实现的:
如果在对集合进行迭代时修改了映射(除非通过迭代器自己的remove操作,或者通过迭代器返回的映射条目上的setValue操作),迭代的结果是未定义的即可。 (重点补充)
答案 1 :(得分:2)
如果你看一下HashMap类,你会看到一个名为'modCount'的字段。这是地图在迭代期间何时被修改的知识。在迭代时增加modCount的任何方法都会导致它抛出ConcurrentModificationException。
也就是说,如果密钥已经存在,您可以将值放入映射中,使用新值有效地更新条目:
Map<String, Object> test = new HashMap<String, Object>();
test.put("test", 1);
for(String key : test.keySet())
{
test.put(key, 2); // this works!
}
System.out.println(test); // will print "test->2"
当您询问是否可以“安全地”执行这些操作时,您不必过于担心,因为HashMap会在遇到类似问题时立即抛出ConcurrentModificationException。这些操作会很快失败;他们不会让地图处于糟糕状态。
答案 2 :(得分:2)
没有全球答案。地图界面允许用户选择。不幸的是,我认为jdk中的所有实现都使用 fail-fast 实现(这里是fail-fast的定义,正如HashMap Javadoc中所述):
所有这些都返回了迭代器 class的“集合视图方法”是 失败快:如果地图是结构性的 之后随时修改 除了以外的任何方式创建迭代器 通过迭代器自己删除 方法,迭代器会抛出一个 ConcurrentModificationException的。从而, 面对并发 修改,迭代器失败 快速而干净,而不是 冒着任意,不确定的风险 在一个不确定的时间的行为 未来。
答案 3 :(得分:0)
通常,如果要在迭代时更改Map,则应使用迭代器的方法之一。我实际上没有测试过看#1是否会起作用,但其他人肯定不会。