У меня есть ArrayList, который я хочу перебрать. Итерируя по нему, я должен удалить элементы одновременно. Очевидно, это бросает java.util.ConcurrentModificationException
.
Какова лучшая практика для решения этой проблемы? Должен ли я сначала клонировать список?
Я удаляю элементы не в самом цикле, а в другой части кода.
Мой код выглядит так:
public class Test() {
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff() {
for (A a : abc)
a.doSomething();
}
public void removeA(A a) {
abc.remove(a);
}
}
a.doSomething
может позвонить Test.removeA()
;
Ответы:
Два варианта:
originalList.removeAll(valuesToRemove)
в концеremove()
метод на самом итераторе. Обратите внимание, что это означает, что вы не можете использовать расширенный цикл for.В качестве примера второй опции, удаляем любые строки длиной более 5 из списка:
источник
Из JavaDocs ArrayList
источник
Вы пытаетесь удалить значение из списка в расширенном цикле for, что невозможно, даже если вы применили какой-то трюк (который вы сделали в своем коде). Лучше всего кодировать уровень итератора, как советуют другие.
Интересно, как люди не предложили традиционный для петли подход.
Это работает также.
источник
Вы действительно должны просто итерировать массив традиционным способом
Каждый раз, когда вы удаляете элемент из списка, элементы после будут перемещаться вперед. Пока вы не измените элементы, отличные от итеративного, следующий код должен работать.
источник
В Java 8 вы можете использовать интерфейс коллекции и сделать это, вызвав метод removeIf:
Более подробную информацию можно найти здесь
источник
Выполните цикл обычным способом,
java.util.ConcurrentModificationException
это ошибка, связанная с элементами, к которым осуществляется доступ.Поэтому постарайтесь:
источник
java.util.ConcurrentModificationException
, не удаляя что-либо из списка. Tricky. :) Вы не можете назвать это «нормальным способом» для перебора списка.Во время итерации списка, если вы хотите удалить элемент, это возможно. Давай посмотрим ниже мои примеры,
У меня есть вышеупомянутые имена списка Array. И я хочу удалить имя "def" из списка выше,
Приведенный выше код вызывает исключение ConcurrentModificationException, поскольку вы изменяете список во время итерации.
Таким образом, чтобы удалить имя "def" из Arraylist, сделав так,
Приведенный выше код, через итератор, мы можем удалить имя «def» из Arraylist и попытаться напечатать массив, вы увидите вывод ниже.
Вывод: [abc, ghi, xyz]
источник
Одним из вариантов является изменение
removeA
метода для этого -Но это означает , что ваш
doSomething()
должен быть в состоянии пройтиiterator
кremove
методу. Не очень хорошая идея.Вы можете сделать это в два этапа: в первом цикле, когда вы перебираете список, вместо удаления выбранных элементов, пометьте их как подлежащие удалению . Для этого вы можете просто скопировать эти элементы (поверхностное копирование) в другой
List
.Затем, как только ваша итерация будет завершена, просто сделайте
removeAll
из первого списка все элементы второго списка.источник
Вот пример, в котором я использую другой список для добавления объектов для удаления, а затем я использую stream.foreach для удаления элементов из исходного списка:
источник
Вместо использования Для каждого цикла используйте обычный цикл for. например, приведенный ниже код удаляет все элементы в списке массивов без предоставления исключения java.util.ConcurrentModificationException. Вы можете изменить условие в цикле в соответствии с вашим вариантом использования.
источник
Сделайте что-нибудь простое, например:
источник
Альтернативное решение Java 8 с использованием потока:
В Java 7 вы можете использовать вместо Guava:
Обратите внимание, что пример Guava приводит к неизменному списку, который может или не может быть тем, что вы хотите.
источник
Вы также можете использовать CopyOnWriteArrayList вместо ArrayList. Это последний рекомендуемый подход, начиная с версии 1.5.
источник
В моем случае принятый ответ не работает, он останавливает исключение, но вызывает некоторые противоречия в моем списке. Следующее решение отлично работает для меня.
В этом коде я добавил элементы для удаления в другой список, а затем использовал
list.removeAll
метод для удаления всех необходимых элементов.источник
"Должен ли я сначала клонировать список?"
Это будет самое простое решение, удалить из клона и скопировать клон обратно после удаления.
Пример из моей игры в руммикуб:
источник
stones = (...) clone.clone();
это излишне. Неstones = clone;
сделал бы то же самое?stones
. Таким образом, вам даже не нужнаclone
переменная:for (Stone stone : (ArrayList<Stone>) stones.clone()) {...
Если ваша цель - удалить все элементы из списка, вы можете выполнить итерацию по каждому элементу, а затем вызвать:
источник
Я опаздываю, я знаю, но я отвечаю на это, потому что я думаю, что это простое и элегантное решение:
Все это для обновления из одного списка в другой, и вы можете сделать все из одного списка, а при обновлении метода вы проверяете оба списка и можете стирать или добавлять элементы между списками. Это означает, что оба списка всегда одного размера
источник
Используйте Iterator вместо Array List
Пусть набор будет преобразован в итератор с типом соответствия
И перейти к следующему элементу и удалить
Здесь важно перейти к следующему, так как для удаления элемента необходим индекс.
источник
Как насчет
источник
Просто добавьте разрыв после вашего заявления ArrayList.remove (A)
источник