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

从ArrayList移除元素时触发ConcurrentModificationException问题求助

解决Java 2D游戏中移除物品时的ConcurrentModificationException

问题原因

从报错栈轨迹能看到,异常发生在GameObjectManager.render方法的集合遍历过程中。这是因为你在遍历gameObjects集合(比如渲染循环里的for-each遍历)的同时,直接调用了集合的remove方法修改它。Java的ArrayList迭代器会检测集合的修改次数(modCount),如果迭代过程中集合被直接修改(不是通过迭代器的remove方法),就会抛出这个异常。另外你原有的碰撞检测逻辑还有个小问题:每次循环遇到非碰撞物品就把collidingItem设为null,最后只会保留最后一个遍历到的碰撞物品,甚至可能变成null。

解决方案

方案1:批量移除(适合单线程场景)

不要在遍历过程中直接修改集合,而是先收集所有需要移除的物品,遍历结束后统一移除:

// 1. 收集所有碰撞的物品并添加到背包
List<ItemObject> itemsToRemove = new ArrayList<>();
for (GameObject obj : goManager.gameObjects) {
    if (obj instanceof ItemObject itemObj) {
        if (bounds().intersects(itemObj.getBounds())) {
            itemsToRemove.add(itemObj);
            inventory.add(itemObj.getItem());
        }
    }
}
// 2. 统一移除,避免遍历中修改集合
goManager.gameObjects.removeAll(itemsToRemove);

方案2:使用线程安全集合(适合多线程场景)

如果你的游戏是多线程架构(比如输入处理和渲染在不同线程),可以把gameObjects换成CopyOnWriteArrayList。这个集合的迭代器基于修改前的快照,迭代时修改集合不会触发异常:

// 把gameObjects的初始化改成CopyOnWriteArrayList
List<GameObject> gameObjects = new CopyOnWriteArrayList<>();

之后你原来的移除代码就可以正常使用了,但注意CopyOnWriteArrayList写操作开销略大,适合读多写少的场景(游戏物品拾取符合这个特点)。

补充:修复原碰撞逻辑的bug

你原来的代码中,每次循环遇到非碰撞物品就重置collidingItem为null,这会导致如果有多个碰撞物品,最后只有最后一个会被记录,甚至遍历到非碰撞物品时collidingItem会变成null。上面的方案1已经通过收集所有碰撞物品解决了这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 17:34:56