Безопасно ли добавлять элементы в связанный список во время итерации?
Безопасно ли добавлять элементы в LinkedList
во время итерации?
class Worker {
final LinkedList<Foo> worklist = new LinkedList<>();
public void work() {
Iterator<Foo> iterator = worklist.iterator();
while (iterator.hasNext()) {
Foo foo = iterator.next();
doSomethingWith(foo);
}
}
public void doSomethingWith(Foo foo) {
// do something with foo
// and possibly add one (or more) foo's to the worklist
if (expression) {
worklist.add(new Foo());
}
}
}
Если нет, как это поведение может быть реализовано безопасным и эффективным способом?
Обратите внимание, что это не оList
, но конкретно о LinkedList
, Если это не безопасно, я спрашиваю об альтернативах.
1 ответ
Нет, это не безопасно. Следующий код бросит ConcurrentModificationException
:
final LinkedList<Foo> worklist = new LinkedList<>();
worklist.add(new Foo());
Iterator<Foo> iterator = worklist.iterator();
while (iterator.hasNext()) {
Foo foo = iterator.next();
worklist.add(new Foo());
}
LinkedList
не переопределяет iterator()
и реализация по умолчанию, определенная в AbstractSequentialList
это позвонить listIterator()
, а также LinkedList
переопределяет listIterator
,
Цитирование документации LinkedList.listIterator
:
Список-итератор работает быстро: если список структурно изменяется в любое время после создания Итератора, любым способом, кроме как через собственный список-итератор
remove
или жеadd
методы, список-итератор будет бросатьConcurrentModificationException
,
То, что вы хотите, это явно использовать ListIterator
вместо Iterator
и использовать ListIterator.add
:
final LinkedList<Foo> worklist = new LinkedList<>();
worklist.add(new Foo());
ListIterator<Foo> iterator = worklist.listIterator();
while (iterator.hasNext()) {
Foo foo = iterator.next();
iterator.add(new Foo());
}
Новый элемент вставляется перед элементом, который был возвращен next()
поэтому последующие звонки next()
не затронуты. Если вы хотите добавить новый элемент в итерацию, вы можете вызвать previous()
(и игнорировать возвращаемое значение) после добавления элемента для перемещения курсора назад.