从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
相关产品推荐
相关产品推荐

