Java HashMap在迭代时添加新条目

15
在HashMap中
map = new HashMap<String,String>();

it = map.entrySet().iterator();
while (it.hasNext())
{
    entry = it.next();
    it.remove(); //safely remove a entry
    entry.setValue("new value"); //safely update current value
    //how to put new entry set inside this map
    //map.put(s1,s2); it throws a concurrent access exception

}

当我尝试向地图中添加新条目时,它会抛出ConcurrentModificationException异常。对于删除和更新,迭代器具有安全的删除方法。如何在迭代时添加新条目?


2
创建一个新的 Map<String, String> foo 实例并在其中设置所需的值。在您的过程结束时,通过使用 map = foo; 将此映射分配给旧映射。 - Luiggi Mendoza
我认为是这样的。没有其他直接的方法,对吧? - Bruce
你可以使用 ConcurrentHashMap 来完成,但这似乎有些过度。此外,使用迭代器来执行这些清理任务并不是一个好的选择。 - Luiggi Mendoza
4个回答

14

在迭代Map时,需要考虑给Map赋值的含义。HashMap没有定义其条目将以何种顺序进行迭代。因此,在放置新条目时,迭代器是否应返回该条目取决于你的决策。一致的行为很重要。但是,无论你如何决定,在向已存在的键中放入新值时都会出现不一致的行为。如果已经迭代过该键,则更改不会出现,而如果迭代器尚未生成该键,则会出现更改。

解决此问题的简单方法是创建一个新的临时Map来存储新的键值对,并在迭代结束时将临时Map添加到主Map中。

Map<String,String> values = ...

Map<String,String> temp = new HashMap<>();
for (Entry<String,String> entry : values.entrySet()) {
    if ("some value".equals(entry.getValue()) {
        temp.put(entry.getValue(), "another value");
    }
}
values.putAll(temp);

一致的行为并非总是需要的,特别是在概率算法中。 - luke1985

3

在遍历集合时添加元素,你需要使用ConcurrentHashMap。HashMap使用快速失败迭代器,当在迭代时更新集合时会抛出ConcurrentModificationException异常。而ConcurrentHashMap使用安全失败迭代器,它基本上是在底层集合的克隆上工作,因此允许在迭代时进行修改。


1
我认为在这种情况下使用ConcurrentHashMap可能有些过头了。 - Luiggi Mendoza

2
如何呢?
map = new HashMap<String,String>();

it = map.entrySet().iterator();
while (it.hasNext())
{
    entry = it.next();
    entry.setValue("new value"); // update current value
}

我检查了HashMap的实现,发现它在更新条目时不会更改其修改计数。我也没有看到为什么不允许这样做的原因。没有任何内容被删除、添加或键被更改。

0
我所做的是创建一个包含当前元素的数组,然后遍历该数组:
Feature[] initialFeatures = featureMap.values().toArray(new Feature[featureMap.values().size()]);

for (Feature feature : initialFeatures)
{/* Code that can safely add to the featureMap */}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接