Почему 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();
}