You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ArrayList迭代器并发修改异常:修改列表内对象内部列表引发问题

分析并修复内部列表修改引发的ConcurrentModificationException

我来帮你拆解这个问题,你遇到的异常并不是多线程并发访问导致的,而是单线程下同一个列表被两个迭代器同时操作,其中一个修改了列表结构引发的快速失败异常。

问题根源

仔细梳理你的代码逻辑就能发现问题所在:

  1. 在interactWithItem方法中,你通过tempIt迭代器正在遍历目标chest的containedItems列表。
  2. 遍历过程中,你调用了removeContainedItem方法,而这个方法又会重新定位到同一个chest的containedItems列表,创建新的迭代器i并执行i.remove()操作。

Java集合的迭代器是**快速失败(fail-fast)**设计:当一个迭代器在遍历列表时,如果列表的结构(元素数量)被修改,且修改不是通过当前迭代器的remove()方法完成的,迭代器就会抛出ConcurrentModificationException。这里tempIt还在遍历,i却修改了同一个列表的结构,自然触发了异常。

你以为内部列表只被当前方法访问,但实际上interactWithItem的迭代器和removeContainedItem的迭代器在同时操作同一个containedItems列表,这就是问题的核心。

修复方案

方案一:直接在当前迭代器中删除元素(最简洁)

既然你已经在遍历chest的containedItems,完全可以直接用当前迭代器的remove()方法删除元素,不需要额外调用removeContainedItem,这样就避免了多个迭代器操作同一个列表的冲突:

public void interactWithItem(int targetIDX, int targetIDY) {
    for(Iterator<Item> it = listOfAllItems.iterator(); it.hasNext();) {
        Item tempItem = it.next();
        if(tempItem.tilePosX == targetIDX && tempItem.tilePosY == targetIDY) {
            if(tempItem.name.equals("chest")) {
                System.out.println("Interacting with Chest!");
                if(!tempItem.containedItems.isEmpty()) {
                    Iterator<Item> tempIt = tempItem.containedItems.iterator();
                    while(tempIt.hasNext()) {
                        Item tItem = tempIt.next();
                        System.out.println("Chest contains "+tItem.name+" "+tItem.amount);
                        Character.c.addItem("player", tItem.name, tItem.amount);
                        // 直接用当前迭代器删除元素,避免跨方法的迭代器冲突
                        tempIt.remove();
                    }
                } else {
                    System.out.println("Chest is empty");
                }
            }
        }
    }
}

方案二:重构removeContainedItem方法(保留复用性)

如果removeContainedItem方法需要在其他地方复用,可以修改它的参数,直接传入容器对象,避免重复遍历listOfAllItems,同时确保修改操作不会和正在进行的遍历冲突:

// 重构后的removeContainedItem:直接接收容器对象
public void removeContainedItem(Item container, String itemName) {
    System.out.println("Removing "+itemName+" in "+container.name);
    Iterator<Item> i = container.containedItems.iterator();
    while(i.hasNext()) {
        Item tempItem = i.next();
        System.out.println(tempItem.name);
        if(tempItem.name.equals(itemName)) {
            i.remove();
        }
    }
}

// 修改interactWithItem:先收集元素,遍历完成后再批量删除
public void interactWithItem(int targetIDX, int targetIDY) {
    for(Iterator<Item> it = listOfAllItems.iterator(); it.hasNext();) {
        Item tempItem = it.next();
        if(tempItem.tilePosX == targetIDX && tempItem.tilePosY == targetIDY) {
            if(tempItem.name.equals("chest")) {
                System.out.println("Interacting with Chest!");
                if(!tempItem.containedItems.isEmpty()) {
                    // 先收集所有要转移的物品
                    List<Item> itemsToTransfer = new ArrayList<>();
                    for(Item tItem : tempItem.containedItems) {
                        itemsToTransfer.add(tItem);
                        System.out.println("Chest contains "+tItem.name+" "+tItem.amount);
                        Character.c.addItem("player", tItem.name, tItem.amount);
                    }
                    // 遍历完成后再批量删除
                    for(Item tItem : itemsToTransfer) {
                        removeContainedItem(tempItem, tItem.name);
                    }
                } else {
                    System.out.println("Chest is empty");
                }
            }
        }
    }
}

这种方式先收集所有要处理的元素,遍历完成后再执行删除操作,避免了遍历过程中修改列表结构的问题。

补充说明

你注释掉i.remove()后异常消失,是因为此时没有修改containedItems的结构,迭代器检测不到结构变化,自然不会触发快速失败异常。

内容的提问来源于stack exchange,提问作者Frost

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:19:24