2015-06-17 2 views
0

Я пытаюсь написать код для моделирования WaTor, в котором акулы и рыба едят друг друга и имитируют управление популяцией и т. Д. В любом случае проблема, с которой я сталкиваюсь, заключается в том, что я продолжаю получать исключение для исключения, даже при использовании итератора ,Исключение одновременной модификации при использовании итератора? (Java)

Вот мой код:

private void updateSharks() { 
    for(Iterator<Shark> sharkit = sharks.iterator(); sharkit.hasNext();) { 
     Shark sharky = sharkit.next(); 
     if(sharky.hasStarved()) { 
      sharkit.remove(); 
     } 
     else if(sharky.canBreed()) { 
      addNewShark(sharky.getX(),sharky.getY()); 
     } 
     moveShark(sharky); 
    } 
} 

и здесь исключение:

Exception in thread "main" java.util.ConcurrentModificationException 
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) 
at java.util.ArrayList$Itr.next(ArrayList.java:851) 
at WaTor.Ocean.updateSharks(Ocean.java:281) 
at WaTor.Ocean.update(Ocean.java:307) 
at WaTor.Main.main(Main.java:13) 

Line 281 в океане "Акула Sharky = sharkit.next();" Спасибо за любую помощь!

+0

Вы не можете изменить коллекцию, перемещая ее с помощью итератора. Проверьте, например, этот ответ, чтобы получить то, что вы хотите: http://stackoverflow.com/q/122105/4250114 –

+1

Я предполагаю, что здесь либо обвиняют 'addNewShark', либо' moveShark'; они, вероятно, получают доступ к коллекции небезопасным способом. –

+1

Кроме того, в отношении вашей трассировки стека: причина, по которой это происходит, заключается в том, что 'Iterator.next' - это когда он проверяет коммодицию (как вы можете догадаться из методов в трассировке). Это не происходит в тот момент, когда вы на самом деле комодифицируете коллекцию. –

ответ

0

Как уже упоминалось, вы не можете изменять коллекцию во время итерации (удалить необязательно). Ну, вы можете собрать всех акул, которые должны умереть в другой коллекции, и удалить их после завершения цикла итератора.

Попробуйте следующее:

private void updateSharks() { 
    ArrayList<Shark> toRemove = new ArrayList<Shark>(); 
    ArrayList<Shark> toAdd = new ArrayList<Shark>(); 

    for(Iterator<Shark> sharkit = sharks.iterator(); sharkit.hasNext();) { 
     Shark sharky = sharkit.next(); 
     if(sharky.hasStarved()) { 
      toRemove.add(sharky); 
     } 
     else if(sharky.canBreed()) { 
      toAdd.add(/*create new shark object here*/) 
     } 
     moveShark(sharky); 
    } 

    for (Shark shark : toRemove) { 
     sharks.remove(shark); 
    } 
    for (Shark shark: toAdd) { 
     sharks.add(shark); 
    } 
} 

EDIT: Как это работает

Вы перебор коллекции. На этом этапе вы можете делать все, что пожелаете, в объектах, содержащихся в коллекции, но вы не можете изменять сам набор, потому что итератор не позволяет вам.

Итак, вы создаете вторую временную коллекцию. Каждый раз, когда вы сталкиваетесь с объектом, который хотите удалить из основной коллекции, вы добавляете этот объект во временную коллекцию. Поскольку в Java передаются только ссылки, и здесь нет глубокого копирования, и это тот же объект, который содержится в двух коллекциях одновременно.

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

+0

будет toRemove все еще признать акулу, которую я добавил к ней, даже после того, как я ее переместил? перемещение акулы просто меняет координаты x и y, но означает ли это, что акула в акулах отличается от акулы in the Remove? – Jared

+0

Нет, это будет та же самая акула. Это потому, что это ссылка на один и тот же объект. – pnadczuk

+0

это работает! Спасибо. если вы не возражаете, я до сих пор не совсем понимаю, как это работает. поэтому я добавляю sharky в toRemove, что относится к голодной акуле. затем я повторяю список акул и перемещаю акул. означает ли это, что sharky in toRemove также переехал, поскольку он ссылается на ту же акулу? – Jared

2

Вы не можете изменять список при его перемещении. Если вы удаляете элементы из списка во время прохождения, то - Один из вариантов исправить это - это удалить эти элементы в другом списке, а затем перебрать этот список для удаления элементов. - Другой вариант - использовать Iterator.remove() Вы используете Iterator.remove(). Так хорошо.

Если вы добавляете элементы во время прохождения, это также может быть проблемой. Я не тестировал ваш код. Но убедитесь, что вы не добавляете элементы для списка акул в методах addNewSharks() и moveSharks()

0

Пожалуйста, посмотрите на JavaDoc для Iterator. Для метода remove вы можете найти следующий текст:

Удаляет из базовой коллекции последний элемент, возвращаемый этим итератором (дополнительная операция). Этот метод можно вызвать только один раз для каждого вызова next(). Поведение итератора не определено, если базовая коллекция изменяется, пока итерация выполняется каким-либо образом, кроме вызова метода ths.

Для меня это похоже, что вы добавляете элементы в коллекцию, итерации по ней. Следовательно, вы можете столкнуться с неуказанным поведением.

0

Не используйте итератор. Перейдите через коллекцию назад следующим образом:

import java.util.ArrayList; 

public class RemoveFromCollectionExample { 

    // 
    // instance variables 
    // 

    private ArrayList<Shark> sharks; 

    // 
    // main 
    // 

    public static void main(String[] args) { 
     RemoveFromCollectionExample example = new RemoveFromCollectionExample(); 
     example.sharks = new ArrayList<RemoveFromCollectionExample.Shark>(); 
     example.addShark(false, false, 0, 0); 
     example.addShark(false, false, 0, 0); 
     example.addShark(false, false, 0, 0); 
     example.addShark(false, false, 0, 0); 
     example.addShark(false, false, 0, 0); 
     example.addShark(false, false, 0, 0); 
     example.addShark(false, true, 0, 0); 
     example.addShark(true, false, 0, 0); 
     example.addShark(true, false, 0, 0); 
     example.addShark(true, false, 0, 0); 
     System.out.println("START WITH: " + example.sharks.size()); 
     example.updateSharks(); 
     System.out.println("Added 1, Removed 3"); 
     System.out.println("ENDED WITH: " + example.sharks.size()); 
    } 

    // 
    // update sharks 
    // 

    private void updateSharks() { 
     for (int i = this.sharks.size() - 1; i > 0; i--) { 
      Shark sharky = this.sharks.get(i); 
      if (sharky.hasStarved()) { 
       this.sharks.remove(i); 
       System.out.println("REMOVED"); 
      } else if (sharky.canBreed()) { 
       addNewShark(sharky.getX(), sharky.getY()); 
       System.out.println("ADDED"); 
      } 
      moveShark(sharky); 
     } 
    } 

    // 
    // add new shark method 
    // 

    private void addNewShark(int x, int y) { 
     this.sharks.add(new Shark(false, false, x, y)); 
    } 

    private void addShark(boolean hasStarved, boolean canBreed, int x, int y) { 
     this.sharks.add(new Shark(hasStarved, canBreed, x, y)); 
    } 

    // 
    // move method 
    // 

    private void moveShark(Shark sharky) { 
    } 

    // 
    // Shark class 
    // 

    private class Shark { 

     private boolean hasStarved; 
     private boolean canBreed; 
     private int x; 
     private int y; 

     public boolean hasStarved() { 
      return hasStarved; 
     } 

     public void setHasStarved(boolean hasStarved) { 
      this.hasStarved = hasStarved; 
     } 

     public boolean canBreed() { 
      return canBreed; 
     } 

     public void setCanBreed(boolean canBreed) { 
      this.canBreed = canBreed; 
     } 

     public int getX() { 
      return x; 
     } 

     public void setX(int x) { 
      this.x = x; 
     } 

     public int getY() { 
      return y; 
     } 

     public void setY(int y) { 
      this.y = y; 
     } 

     public Shark(boolean hasStarved, boolean canBreed, int x, int y) { 
      super(); 
      this.hasStarved = hasStarved; 
      this.canBreed = canBreed; 
      this.x = x; 
      this.y = y; 
     } 

     public void moveShark() { 
     } 

    } 

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