java - 如何在 HashMap 上使用双迭代器修复“java.util.ConcurrentModificationException”
问题描述
如果它们验证彼此之间的条件,我想“合并”同一哈希图的元素。
“合并”的意思是:将自己的属性相加。
如果 2 个 Item 被合并,我们应该从 hashmap 中删除第二个,因为它已被集成到第一个中。
此操作必须高效,因为地图可能包含大量元素。
public static void main(String[] args) {
Map<Long, Item> itemMap = new HashMap(){
{
put(0L, new Item(2558584));
put(1L, new Item(254243232));
put(2L, new Item(986786));
put(3L, new Item(672542));
put(4L, new Item(48486));
put(5L, new Item(76867467));
put(6L, new Item(986786));
put(7L, new Item(7969768));
}
};
Iterator it_I = itemMap.entrySet().iterator();
while (it_I.hasNext()) {
Map.Entry pair_I = (Map.Entry)it_I.next();
Item tempItem_I = (Item)pair_I.getValue();
System.out.println("I:" + tempItem_I);
Iterator it_J = itemMap.entrySet().iterator();
while (it_J.hasNext()) {
Map.Entry pair_J = (Map.Entry)it_J.next();
Item tempItem_J = (Item)pair_J.getValue();
if (!pair_J.getKey().equals(pair_I.getKey())) {
boolean isSame = tempItem_I.isSame(tempItem_J);
if(isSame){
tempItem_I.merge(tempItem_J);
it_J.remove();
}
}
}
}
}
public class Item {
long id;
public Item(long id) {
this.id = id;
}
public boolean isSame(Item item) {
if(this.id == item.id) return true;
else return false;
}
public void merge(Item item) {
this.id += item.id;
}
public String toString() {
return String.valueOf(this.id);
}
}
只有包含 id: 986786 的 2 个 Item 可以合并在一起,因为它们验证了要合并的条件(相同的 id)。
但是无法删除它:
Exception in thread "main" java.util.ConcurrentModificationException I:2558584 I:254243232 at java.util.HashMap$HashIterator.nextNode(HashMap.java:1445) I:986786 at java.util.HashMap$EntryIterator.next(HashMap.java:1479) at java.util.HashMap$EntryIterator.next(HashMap.java:1477) at Main.main(Main.java:23)
解决方案
这是一种更线性的方法来解决这个问题,使用额外的 Map 来跟踪项目标识符是否
Map<Long, Long> reversed = new HashMap<>();
Iterator<Map.Entry<Long, Item>> iterator = itemMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<Long, Item> pair = iterator.next();
Long itemKey = reversed.get(pair.getValue().id);
if (itemKey != null) {
Item item = itemMap.get(itemKey);
item.merge(pair.getValue());
iterator.remove();
} else {
reversed.put(pair.getValue().id, pair.getKey());
}
}