2014-02-17 2 views
0

Жильцы - это java.util.ArrayList.Итератор Arraylist: одновременная модификация

Я итерация через него, как так

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()' iterator в своей собственной итерации, так что это не проблема. –

+1

Да, что делает метод 'hit'? Вставьте код. – mrres1

ответ

0

Hitable.hit() добавляет элемент в массив, тем самым вызывая одновременное изменение.

Чтобы поместить это в контекст:

Я делаю классическую игру змея.Когда змея попадает в Набегающее яблоко: 1) Яблоко должно быть удалено из обитателей BoardSpace // BoardSpace == tile это делается в коде, обсуждаемом здесь 2) Тело змеи удлиняется в BoardSpace, где яблоко был. Змея теперь является обитателем BoardSpace, поэтому змея добавляется к обитателям.

Оба они выполняются внутри Apple.hit(), ergo: одновременная модификация.

Решение: Я использовал экземпляр 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. Это имеет значение, потому что, повторяя, оно может легко привести к исключению вне пределов, если вы должны сократить длину списка без повторной настройки итератора.

Существует множество способов обойти это, но существует постоянное правило: если вы итерации, вы не можете удалить. Поэтому либо подумайте о том, как сделать это, не итерируя (цикл while, который только увеличивает индекс, когда hitable.hit является ложным), или сохраняет объекты, которые нужно удалить в отдельном списке, а затем удалять эти элементы по одному.

+1

Это совершенно и совершенно неверно. OP использует метод 'remove()' итератора. Почему вы думаете, что 'ListIterator' и' Iterator' имеют 'remove()' методы? На самом деле у вас есть *, чтобы использовать метод remove() итератора, чтобы удалить что-то из списка во время итерации через него, чтобы он мог справляться с описанными вами проблемами. –

+0

Вы правы. Я ошибочно прочитал, что исходный код имел .remove(), прежде чем выпустить его .next(), который (по крайней мере в прошлом) вызовет эту ошибку. Но код находится в правильном порядке. – gravityplanx

0

ConcurrentModificationException в соответствии с ява документы

Это исключение может быть выброшено с помощью методов, которые обнаруженных одновременного модификации объекта, когда такое изменение не допускается.

Например, для одного потока обычно не допускается изменять a Collection, в то время как другой поток выполняет итерацию по нему. В общем случае результаты итерации в этих условиях не определены. Некоторые реализации Итератора (в том числе и для всех общих реализаций набора , предоставленных JRE) могут выбрать , если это обнаружение обнаружит это исключение. Итераторы, которые делают , известны как отказоустойчивые итераторы, так как они не срабатывают быстро и чисто, а скорее рискуют произвольным, недетерминированным поведением на неопределенное время в будущем.

Вкратце, вы не можете изменить список при повторении через него.

Есть несколько способов:

1) Создать новый список

2) Использование различных коллекций, таких как карты или Set.

3) Изменение в какое-то состояние объекта hitable

+0

Вы можете с радостью изменить список во время итерации через него, пока вы используете метод remove() итератора, который OP; для чего это нужно. Его проблема на самом деле * что-то еще * изменение списка в то же время. –

+0

@BrianRoach, поэтому я пропустил понимание других ответов или все они неверны? Я не часто использую ArrayList verry (на самом деле я играю с libgdx, поэтому я использую свой массив) – Springrbua

+1

@BrianRoach ah okay теперь я понимаю: P Если вы используете итераторы remove(), это нормально, поскольку это было сделано для этого. Мне нужно подумать об этом перед публикацией ... Я удалил свой вводящий в заблуждение комментарий – Springrbua

Смежные вопросы