Почему Iterator.next() выбрасывает ConcurrentModificationException

Как ни странно, этот маленький кусок кода бросает вышеупомянутое исключение. Кроме того, просмотр кода, размещенного по сети, кажется правильным:

import java.util.ArrayList;
import java.util.Iterator;

public class IteratorTest {

    ArrayList<Integer> arr = new ArrayList<Integer>();

    Iterator i = arr.iterator();

    public void show() {
        arr.add(2);
        arr.add(5);
        arr.add(9);

        while(i.hasNext()){
            System.out.println(i.next());
        }
    }
}

Любые советы? Благодаря

Ответ 1

Этот вызов:

Iterator i=arr.iterator();

должен быть после того, как вы выполнили все записи в своем ArrayList.

Итак, в своем коде сделайте это перед тем, как начать итерацию следующим образом:

Iterator i=arr.iterator();
while(i.hasNext()) {
...
}

Ответ 2

Это потому, что вы изменили список поддержки между получением Iterator через iterator() и вызовом next().

Типичное использование Итератора:

for (Iterator<Integer> iter=arr.iterator(); iter.hasNext(); ) {
    Integer element = iter.next();
}

Или еще лучше, используйте новый для каждого цикла:

for (Integer element: arr) {
}

Обязательно выполняйте дополнения к коллекции вне цикла.

Ответ 3

Вы определяете Iterator при создании объекта, IteratorTest. Затем вы добавляете некоторые данные в ArrayList, arr.

Теперь вы изменили свой список, и, следовательно, состояние Iterator недействительно.

Вы не можете использовать Iterator и изменить ArrayList, не используя Iterator, чтобы сделать это.

Ответ 4

Ответ 4 технически корректен, но не потому, что вместо цикла while() используется цикл for(;;) или "для каждого". Это просто вопрос объявленной области Iterator внутри класса, а не метода. Сначала рассмотрим поведение двух методов hasNext() и next():

Метод hasNext() просто запрашивает внутренний курсор (индекс); next() фактически продвигает курсор, поэтому это "модификация", которая может вызвать исключение. Если вы попытаетесь использовать объявленный и назначенный Iterator вне метода, в котором используется next(), код будет генерировать исключение в первом next(), независимо от того, является ли оно for(;;) или while().

В ответах 4 и 8 итератор объявляется и потребляется локально внутри метода. Так получилось, так как конструктор for(;;) допускает объявление первого времени и назначение итератора до выполнения цикла (что делает итератор привязан к for(;;) и неявно внутри метода, делая его "безопасным" ). Я согласен с тем, что идиома for(;;) чище синтаксически и ограничивает область действия на самом низком уровне выполнения, полностью в цикле for(;;).

Ответ 8 правильный, потому что Итератор назначается и используется локально внутри метода.

Но, только для обсуждения, следующий метод, использующий оператор while(), синтаксически корректен, "безопасен" и не модифицируется из области видимости и ссылки:

где-то в определении класса ...

ArrayList<String> messageList;

где-нибудь в конструкторе класса

messageList = new ArrayList<String>(); 

добавить метод...

public printMessages ( )
{

  Iterator<String> messageIterator = messageList.iterator();

  while (messageIterator.hasNext())
     {
     System.out.println(messageIterator.next());
     }

  System.out.flush();

}