在编写一个简单的游戏时,我遇到了并发修改异常,所以我看了一下,发现了两种不同的修复方法。它起作用了,但是,由于未知原因,只有当玩家调用该函数而不是AI玩家调用(相同)函数时。
该函数的1.0版看起来像这样:
public void eat(ArrayList<Enemy> enemys) {
ArrayList<Enemy> toRemove = new ArrayList<Enemy>();
for(Enemy enemy : enemys) {
if(enemy.location.x != location.x && enemy.location.y != location.y) { //check for self
if(collidesWith(enemy)) {
if(width > enemy.width) {
width += enemy.width;
height = width;
toRemove.add(enemy);
}
}
}
}
enemys.removeAll(toRemove);
}
因为这不起作用,我尝试使用迭代器,不幸的是,它产生了完全相同的错误:
public void eat(ArrayList<Enemy> enemys) {
for(Iterator<Enemy> iterator = enemys.iterator(); iterator.hasNext();) {
Enemy enemy = iterator.next();
if(enemy.location.x != location.x && enemy.location.y != location.y) { //check for self
if(collidesWith(enemy)) {
if(width > enemy.width) {
width += enemy.width;
height = width;
iterator.remove(); //remove the enemy
}
}
}
}
}
错误消息是:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at Main.runGame(Main.java:59)
at Main.<init>(Main.java:43)
at Main.main(Main.java:68)
提前致谢
-v0xelDev
编辑:正如Abishek Manoharan要求runGame()方法,这里是:public void runGame() {
for(Enemy enemy : enemys) {
enemy.eat(enemys);
enemy.update();
}
player.eat(enemys);
player.update();
}
答案 0 :(得分:1)
这是问题所在:
for(Enemy enemy : enemys) {
enemy.eat(enemys);
enemy.update();
}
吃掉会改变你正在迭代的敌人。
答案 1 :(得分:1)
可能的解决办法......
public List eat(ArrayList<Enemy> enemys) {
ArrayList<Enemy> toRemove = new ArrayList<Enemy>();
for(Enemy enemy : enemys) {
if(enemy.location.x != location.x && enemy.location.y != location.y) { //check for self
if(collidesWith(enemy)) {
if(width > enemy.width) {
width += enemy.width;
height = width;
toRemove.add(enemy);
}
}
}
}
return toRemove;
}
public void runGame() {
for(Enemy enemy : enemys) {
List eaten = enemy.eat(enemys);
enemy.update();
}
enemys.removeAll(eaten);
player.eat(enemys);
player.update();
}
答案 2 :(得分:0)
堆栈跟踪在方法Main.java
中将异常的位置放在runGame()
的第59行。这一行显然是循环的一部分,循环遍历一个被修改而不是通过控制Iterator
的集合。如果从该循环中注释掉eat()
的调用可以解决问题,则必须是传递给该方法的参数引用正在迭代的同一个集合。所以不要这样做。
eat()
的第二个代码有更好的形式,但它没有解决问题,这与调用树中某个地方的迭代有关。
如何修复它取决于您想要的行为。特别是,如果你想避免因为有机会吃掉其他敌人而被吃掉的enemy
(正如你现在的代码所做的那样),那么你需要更复杂的东西。另一方面,如果你希望每个敌人都有机会,即使它本身就在游戏时钟的这个刻度上被吃掉,那么你可以使用enemys
集合的副本,也许是这样:< / p>
public void runGame() {
List<Enemy> enemysCopy = new ArrayList<>(enemys);
for(Enemy enemy : enemys) {
enemy.eat(enemysCopy);
}
enemys.retainAll(enemysCopy);
player.eat(enemys);
player.update();
}