Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Мы все знаем, что из-за ConcurrentModificationException вы не можете делать 9X_java следующее:

for (Object i : l) { if (condition(i)) { l.remove(i); } } 

Но иногда это срабатывает, но 9X_oraclejdk не всегда. Вот конкретный код:

public static void main(String[] args) { Collection l = new ArrayList<>(); for (int i = 0; i < 10; ++i) { l.add(4); l.add(5); l.add(6); } for (int i : l) { if (i == 5) { l.remove(i); } } System.out.println(l); } 

Это, конечно 9X_iteration же, приводит к:

Exception in thread "main" java.util.ConcurrentModificationException 

Даже если несколько потоков 9X_jdk этого не делают. В любом случае.

Как лучше 9X_collection всего решить эту проблему? Как я могу удалить 9X_oraclejdk элемент из коллекции в цикле, не вызывая 9X_collections этого исключения?

Я также использую здесь 9X_j2se произвольный Collection, не обязательно ArrayList, поэтому 9X_java-se вы не можете полагаться на get.

1283
1

  • Примечание для читателей: прочтите http://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html, там может быть более простой способ до ...
17
Общее количество ответов: 17

Ответ #1

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Iterator.remove() безопасен, вы можете использовать его так:

List list = new ArrayList<>(); // This is a clever way to create the iterator and call iterator.hasNext() like // you would do in a while-loop. It would be the same as doing: // Iterator iterator = list.iterator(); // while (iterator.hasNext()) { for (Iterator iterator = list.iterator(); iterator.hasNext();) { String string = iterator.next(); if (string.isEmpty()) { // Remove the current element from the iterator and the list. iterator.remove(); } } 

Обратите 9X_java-collections-api внимание, что Iterator.remove() - единственный безопасный 9X_java-api способ изменить коллекцию во время итерации; поведение 9X_core-java не определено, если базовая коллекция изменяется 9X_java любым другим способом во время выполнения итерации.

Источник: docs.oracle > The Collection Interface


И 9X_java-collections-api аналогично, если у вас есть ListIterator и вы хотите 9X_iteration добавить элементы, вы можете использовать ListIterator#add по той 9X_.java же причине, по которой вы можете использовать 9X_.java Iterator#remove - он предназначен для этого.


В вашем случае 9X_java-api вы пытались удалить из списка, но то же 9X_.java ограничение применяется при попытке вставить 9X_iteration put в Map при повторении его содержимого.

1661
5

  • Имейте в виду, что это медленнее по сравнению с ...

Ответ #2

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Это работает:

Iterator iter = l.iterator(); while (iter.hasNext()) { if (iter.next() == 5) { iter.remove(); } } 

Я предположил, что, поскольку 9X_jre цикл foreach является синтаксическим сахаром 9X_iterative для итерации, использование итератора не 9X_java поможет ... но он дает вам эту функцию .remove().

357
2

  • +1, например, код для использования iter.remove() в контексте, которого в ответе Билла ...

Ответ #3

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

В Java 8 вы можете использовать the new removeIf method. Применяется 9X_java-se к вашему примеру:

Collection coll = new ArrayList<>(); //populate coll.removeIf(i -> i == 5); 

234
2

  • @omerhakanbilici Некоторые реализации, такие как `ArrayList`, п ...

Ответ #4

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Поскольку на вопрос уже дан ответ, т.е. лучший 9X_j2se способ - использовать метод удаления объекта 9X_.java итератора, я бы подробно остановился на 9X_collections том месте, где возникает ошибка "java.util.ConcurrentModificationException".

Каждый 9X_java класс коллекции имеет частный класс, который 9X_java-api реализует интерфейс Iterator и предоставляет 9X_java-libraries такие методы, как next(), remove() и hasNext().

Код для next выглядит 9X_java-se примерно так ...

public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch(IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } 

Здесь метод checkForComodification реализован 9X_java-api как

final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } 

Итак, как видите, если вы явно попытаетесь 9X_java-libraries удалить элемент из коллекции. В результате 9X_iterative modCount отличается от expectedModCount, что приводит к исключению 9X_core-java ConcurrentModificationException.

44
1

  • Очень интересно. Спасибо! Я часто сам не вызываю remove(), вместо этого я предпочитаю очищать коллекцию после ее итерации. Не сказать, что это хороший образец, прос ...

Ответ #5

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Вы можете использовать итератор напрямую, как 9X_java-api вы упомянули, или сохранить вторую коллекцию 9X_java и добавить каждый элемент, который вы хотите 9X_collections удалить, в новую коллекцию, а затем удалитьAll 9X_.java в конце. Это позволяет вам продолжать использовать 9X_java-collections-api типобезопасность цикла for-each за счет 9X_openjdk увеличения использования памяти и времени 9X_jre процессора (не должно быть большой проблемой, если 9X_java-api у вас нет действительно очень больших списков 9X_java-collections-api или действительно старого компьютера)

public static void main(String[] args) { Collection l = new ArrayList(); Collection itemsToRemove = new ArrayList<>(); for (int i=0; i < 10; i++) { l.add(Integer.of(4)); l.add(Integer.of(5)); l.add(Integer.of(6)); } for (Integer i : l) { if (i.intValue() == 5) { itemsToRemove.add(i); } } l.removeAll(itemsToRemove); System.out.println(l); } 

28
3

  • Достаточно справедливо, если вы больше ничего не делаете с итератором - его раскрытие упрощает выполнение таких вещей, как call .next() д ...

Ответ #6

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

В таких случаях распространенным трюком 9X_iterative является (был?) возврат назад:

for(int i = l.size() - 1; i >= 0; i --) { if (l.get(i) == 5) { l.remove(i); } } 

Тем не менее, я 9X_jre более чем счастлив, что у вас есть лучшие 9X_collections способы использования Java 8, например removeIf или 9X_java-api filter в потоках.

19
2

  • индексы отличные. Если это так часто, почему бы вам не использовать `fo ...

Ответ #7

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Тот же ответ, что и у Claudius с циклом for:

for (Iterator
   it = objects.iterator(); it.hasNext();) { Object object = it.next(); if (test) { it.remove(); } } 

9X_javax

17
0

Ответ #8

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

С Eclipse Collections будет работать метод removeIf, определенный в 9X_java MutableCollection:

MutableList list = Lists.mutable.of(1, 2, 3, 4, 5); list.removeIf(Predicates.lessThan(3)); Assert.assertEquals(Lists.mutable.of(3, 4, 5), list); 

С синтаксисом Java 8 Lambda это можно записать 9X_java-api следующим образом:

MutableList list = Lists.mutable.of(1, 2, 3, 4, 5); list.removeIf(Predicates.cast(integer -> integer < 3)); Assert.assertEquals(Lists.mutable.of(3, 4, 5), list); 

Вызов Predicates.cast() здесь необходим, поскольку 9X_openjdk метод removeIf по умолчанию был добавлен в интерфейс 9X_javax java.util.Collection в Java 8.

Примечание. Я являюсь коммиттером Eclipse Collections.

12
0

Ответ #9

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Сделайте копию существующего списка и перебирайте 9X_java-libraries новую копию.

for (String str : new ArrayList(listOfStr)) { listOfStr.remove(/* object reference or index */); } 

11
2

  • @Antzi Это зависит от размера списка и плотности объектов внутри. Тем не м ...

Ответ #10

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

С традиционным циклом for

ArrayList myArray = new ArrayList<>(); for (int i = 0; i < myArray.size(); ) { String text = myArray.get(i); if (someCondition(text)) myArray.remove(i); else i++; } 

9X_core-java

10
1

  • Ах, так что это действительно просто _enhanced_-for-loop, ...

Ответ #11

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Люди утверждают, что невозможно удалить из коллекции, повторяемой 9X_iteration циклом foreach. Я просто хотел указать, что 9X_iterative это технически неверно, и точно описать (я знаю, что 9X_iterative вопрос OP настолько сложен, чтобы не знать 9X_collections об этом) код, лежащий в основе этого предположения:

for (TouchableObj obj : untouchedSet) { // <--- This is where ConcurrentModificationException strikes if (obj.isTouched()) { untouchedSet.remove(obj); touchedSt.add(obj); break; // this is key to avoiding returning to the foreach } } 

Дело 9X_java-api не в том, что вы не можете удалить из повторяемого 9X_java-collections-api Colletion, а в том, что вы не можете продолжить итерацию, как 9X_iterative только вы это сделаете. Следовательно, break в 9X_javax приведенном выше коде.

Приносим извинения, если 9X_iteration этот ответ является несколько специализированным 9X_core-java вариантом использования и больше подходит 9X_jdk для исходного thread, откуда я пришел, этот ответ 9X_java-collections-api отмечен как дубликат (несмотря на то, что 9X_collections эта ветка выглядит более тонкой) этого и 9X_javax заблокирована.

10
0

Ответ #12

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

ConcurrentHashMap или ConcurrentLinkedQueue или ConcurrentSkipListMap могут быть другим вариантом, потому 9X_collection что они никогда не вызовут никаких исключений 9X_core-java ConcurrentModificationException, даже если 9X_oraclejdk вы удалите или добавите элемент.

4
0

Ответ #13

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Другой способ - использовать копию вашего 9X_java-api arrayList только для итерации:

List
   l = ... List
     iterationList = ImmutableList.copyOf(l); for (Object curr : iterationList) { if (condition(curr)) { l.remove(curr); } } 
   

4
2

  • Примечание: i - это не ин ...

Ответ #14

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

ListIterator позволяет добавлять или удалять элементы 9X_java-se в списке. Предположим, у вас есть список 9X_jre объектов Car:

List cars = ArrayList<>(); // add cars here... for (ListIterator carIterator = cars.listIterator(); carIterator.hasNext(); ) { if () { carIterator().remove() } else if () { carIterator().add(aNewCar); } } 

2
0

Ответ #15

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Я знаю, что этот вопрос слишком стар, чтобы 9X_java-api касаться Java 8, но для тех, кто использует 9X_j2se Java 8, вы можете легко использовать removeIf():

Collection l = new ArrayList(); for (int i=0; i < 10; ++i) { l.add(new Integer(4)); l.add(new Integer(5)); l.add(new Integer(6)); } l.removeIf(i -> i.intValue() == 5); 

1
0

Ответ #16

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Теперь вы можете удалить с помощью следующего 9X_iteration кода

l.removeIf(current -> current == 5); 

1
0

Ответ #17

Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле

Исключение одновременного изменения

  1. Однонитка
Iterator iterator = list.iterator(); while (iterator.hasNext()) { String value = iter.next() if (value == "A") { //throws ConcurrentModificationException list.remove(it.next()); } } 

Решение: метод итератора remove()

Iterator iterator = list.iterator(); while (iterator.hasNext()) { String value = iter.next() if (value == "A") { it.remove() } } 
  1. Многопоточность
  • копировать / преобразовывать и перебирать еще одну коллекцию. Для небольших коллекций
  • synchronize [About]
  • потокобезопасная коллекция [About]

9X_javax

1
0