2014-02-17 114 views
0

居住者是java.util.ArrayList中。ArrayList的迭代器:concurrentmodification

我遍歷,它像這樣

public void hitOccupants(SnakeController snakeController){ 

    ListIterator<Hitable> i = occupants.listIterator(); 
    while(i.hasNext()){ 
     Hitable hitable = i.next(); 
     if(hitable.hit(snakeController)){//returns true if it should be deleted 
      i.remove(); 
     } 
    } 
} 

我可以找出爲什麼這會給出一個ConcurrenModificationException ... 我使用libgdx,所以有可能是一個線程問題。這是我的第一個libgdx項目,所以我不確定。在android上運行代碼。 Stacktrace:

java.util.ConcurrentModificationException 
     at java.util.AbstractList$SimpleListIterator.remove(AbstractList.java:71) 
     at com.ninovanhooff.snake.model.BoardSpace.hitOccupants(BoardSpace.java:65) 
     at com.ninovanhooff.snake.controller.SnakeController.act(SnakeController.java:77) 
     at com.ninovanhooff.snake.controller.BoardController.act(BoardController.java:72) 
     at com.ninovanhooff.snake.GameActor$2.act(GameActor.java:77) 
     at com.badlogic.gdx.scenes.scene2d.Actor.act(Actor.java:86) 
     at com.badlogic.gdx.scenes.scene2d.Group.act(Group.java:48) 
     at com.badlogic.gdx.scenes.scene2d.Group.act(Group.java:48) 
     at com.badlogic.gdx.scenes.scene2d.Stage.act(Stage.java:225) 
     at com.ninovanhooff.snake.SnakeGame.render(SnakeGame.java:66) 
     at com.badlogic.gdx.backends.android.AndroidGraphics.onDrawFrame(AndroidGraphics.java:510) 
     at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516) 
     at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240) 
+2

Hitable.hit修改列表嗎? – immibis

+0

是的,當你迭代它時,別的東西正在修改列表。你在迭代中正確使用迭代器的remove()方法,所以這不是問題。 –

+1

是的,「hit」方法有什麼作用?粘貼代碼。 – mrres1

回答

0

Hitable.hit()添加到數組中的元素更改一些狀態,因此引起併發修改。

要放置到這個方面:

我提出的經典蛇遊戲。當蛇打Hitable蘋果: 1)蘋果已經從BoardSpace乘員// BoardSpace ==瓦 這是在這裏 2討論)的代碼做蛇的身體被拉長到BoardSpace其中蘋果移除是。蛇現在是BoardSpace的佔有者,因此蛇被添加到佔用者。

這兩個被內Apple.hit完成(),麥角:併發修改。

解決方案:我用的CopyOnWriteArrayList到特拉沃乘員在原始順序和內容,並增加了對以後去除要刪除的元素。

CopyOnWriteArrayList<Hitable> occupantsSnapshot = new CopyOnWriteArrayList<Hitable>(occupants); 
    ArrayList<Hitable> removals = new ArrayList<Hitable>(); 
    Iterator<Hitable> i = occupantsSnapshot.iterator(); 
    while (i.hasNext()) { 
     Hitable hitable = i.next(); 
     boolean remove = hitable.hit(snakeController); 
     if (remove) {//returns true if it should be deleted 
      removals.add(hitable); 
     } 
    } 

    for(Hitable hitable: removals){ 
     occupants.remove(hitable); 
     boardController.removeHitable(hitable); 
    } 

教育目的:Bitbucket snapshot

見AppleController和SnakeBodyParts。

-1

在迭代它時,您不允許從ArrayList中刪除項目。這是由於許多原因造成的。最明顯的是,一個ArrayList是動態的,所以如果你刪除索引2處的對象,那麼索引3處的對象現在向下移動到索引2.這很重要,因爲在迭代時,如果發生異常,很容易導致出界限異常您不必重新調整迭代器即可縮短列表的長度。

有許多的方式來解決這個問題,但有一個常設的規則:如果你迭代,你不能刪除。因此,想辦法做到不迭代(只有在hitable.hit爲false時纔會增加索引的while循環),或將要刪除的對象存儲在單獨的列表中,然後逐個刪除這些項目。

+1

這是完全錯誤的。 OP使用迭代器的remove()方法。你爲什麼認爲'ListIterator'和'Iterator'有'remove()'方法?事實上,你有*要使用迭代器的remove()方法從列表中刪除某些內容,同時遍歷它,以便處理你描述的問題。 –

+0

你是對的。我錯誤地讀到,原始代碼在發佈.next()之前有一個.remove(),它至少在過去會導致這個錯誤。但是代碼的順序是正確的。 – gravityplanx

0

ConcurrentModificationException的按Java文檔

此異常可能由已檢測到的併發 修改一個對象的當這樣的修改是不允許的方法被拋出。

例如,它不是通常用於允許一個線程來修改 集合而另一個線程被遍歷它。一般而言,在這些情況下迭代的結果是不確定的。如果檢測到這種行爲 一些迭代器實現(包括那些由JRE提供的所有一般 用收集實現的),可以選擇 拋出此異常。那些 這被稱爲快速失敗迭代器,因爲它們快速失敗迭代器 乾淨,而,在 冒着任意的,不確定性的行爲在將來不確定的時間。同時,通過它迭代

總之一個不能修改列表。

有多種方式:

1)創建一個新的列表

2)使用不同的集合,如地圖或一組。

3)在hitable對象

+0

只要您使用OP所在的迭代器的remove()方法,您可以在遍歷整個列表時愉快地修改列表;這就是它的目的。他的問題實際上是*別的東西*同時修改列表。 –

+0

@BrianRoach所以我想知道其他答案,或者他們都不正確?我不經常使用ArrayList(實際上我正在玩libgdx,所以我使用他們的數組) – Springrbua

+1

@BrianRoach啊好吧現在我明白了:P如果你使用迭代器remove()它沒關係,因爲它是爲了這個。我需要在發佈前仔細考慮它......我刪除了我的誤導性評論 – Springrbua