Итерации по коллекции, избегая исключения 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
.
- Примечание для читателей: прочтите http://docs.oracle.com/javase/tutorial/collections/interfaces/collection.html, там может быть более простой способ до ...
Ответ #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
при повторении его содержимого.
- Имейте в виду, что это медленнее по сравнению с ...
Ответ #2
Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле
Это работает:
Iterator iter = l.iterator();
while (iter.hasNext()) {
if (iter.next() == 5) {
iter.remove();
}
}
Я предположил, что, поскольку 9X_jre цикл foreach является синтаксическим сахаром 9X_iterative для итерации, использование итератора не 9X_java поможет ... но он дает вам эту функцию .remove()
.
- +1, например, код для использования iter.remove() в контексте, которого в ответе Билла ...
Ответ #3
Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле
В Java 8 вы можете использовать the new removeIf
method. Применяется 9X_java-se к вашему примеру:
Collection coll = new ArrayList<>();
//populate
coll.removeIf(i -> i == 5);
- @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
.
- Очень интересно. Спасибо! Я часто сам не вызываю 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);
}
- Достаточно справедливо, если вы больше ничего не делаете с итератором - его раскрытие упрощает выполнение таких вещей, как 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
в потоках.
- индексы отличные. Если это так часто, почему бы вам не использовать `fo ...
Ответ #7
Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле
Ответ #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.
Ответ #9
Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле
Сделайте копию существующего списка и перебирайте 9X_java-libraries новую копию.
for (String str : new ArrayList(listOfStr))
{
listOfStr.remove(/* object reference or index */);
}
- @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
- Ах, так что это действительно просто _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 заблокирована.
Ответ #12
Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле
ConcurrentHashMap или ConcurrentLinkedQueue или ConcurrentSkipListMap могут быть другим вариантом, потому 9X_collection что они никогда не вызовут никаких исключений 9X_core-java ConcurrentModificationException, даже если 9X_oraclejdk вы удалите или добавите элемент.
Ответ #13
Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле
Другой способ - использовать копию вашего 9X_java-api arrayList только для итерации:
List
- Примечание: 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);
}
}
Ответ #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);
Ответ #16
Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле
Теперь вы можете удалить с помощью следующего 9X_iteration кода
l.removeIf(current -> current == 5);
Ответ #17
Ответ на вопрос: Итерации по коллекции, избегая исключения ConcurrentModificationException при удалении объектов в цикле
Исключение одновременного изменения
- Однонитка
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()
}
}
- Многопоточность
- копировать / преобразовывать и перебирать еще одну коллекцию. Для небольших коллекций
-
synchronize
[About] - потокобезопасная коллекция [About]
9X_javax
-
47
-
6
-
6
-
9
-
3
-
2
-
6
-
4
-
11
-
4
-
8
-
6
-
7
-
7
-
11
-
4
-
8
-
6
-
4
-
13
-
8
-
4
-
13
-
5
-
5
-
3
-
5
-
10
-
7
-
2
-
2
-
10
-
4
-
6
-
8
-
4
-
5
-
9
-
3
-
10
-
7
-
6
-
5
-
3
-
1
-
8
-
18
-
5
-
11
-
27