首页 > 解决方案 > 如何在 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)

标签: java

解决方案


这是一种更线性的方法来解决这个问题,使用额外的 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());
    }
}

推荐阅读