2015-06-12 73 views
1

編寫一個簡單的遊戲時,我遇到了一個併發修改異常,所以我查看了這裏,發現了兩種不同的方法來修復它。它起作用了,但是,由於未知的原因,只有當玩家調用該函數時,而不是在AI玩家調用(相同)函數時。[Java]併發修改異常;迭代器不起作用

功能的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馬諾哈蘭要求的runGame()方法,那就是:

public void runGame() { 
    for(Enemy enemy : enemys) { 
     enemy.eat(enemys); 
     enemy.update(); 
    } 
    player.eat(enemys); 
    player.update(); 
} 
+0

是否使用多個線程? – assylias

+0

@assylias當前沒有 – v0xelDev

+2

它是如何將錯誤歸入方法'eat()',但該方法不會出現在您的堆棧跟蹤中? –

回答

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(); 
} 
0

的堆棧跟蹤的Main.java線59將異常的位置,在方法runGame()。該行顯然是循環的一部分,該循環遍歷一個已被修改的集合,而不是通過控制Iterator。如果從該循環中註釋掉eat()的調用可解決該問題,那麼必須將傳遞給該方法的參數引用到正在迭代的相同集合。所以不要這樣做。

eat()的第二個代碼有更好的形式,但它沒有解決問題,它與呼叫樹上的某處迭代有關。

你應該如何修復它取決於你想要的行爲。特別是,如果你想避免enemy被吃掉而有機會吃掉其他敵人(就像你當前的代碼試圖做的那樣),那麼你需要更復雜的東西。在另一方面,如果你想每一個敵人來獲得它的機會,哪怕是自己在這個滴答比賽計時鐘的吃了,然後你可以用enemys集合的副本進行工作,也許像這樣:

public void runGame() { 
    List<Enemy> enemysCopy = new ArrayList<>(enemys); 

    for(Enemy enemy : enemys) { 
     enemy.eat(enemysCopy); 
    } 
    enemys.retainAll(enemysCopy); 
    player.eat(enemys); 
    player.update(); 
} 
1

這就是問題所在:

for(Enemy enemy : enemys) { 
    enemy.eat(enemys); 
    enemy.update(); 
} 

的吃會改變你與迭代通過敵人。