Как изменить коллекцию во время итерации с использованием цикла для каждого без ConcurrentModificationException?

Если я изменяю коллекцию во время итерации с использованием цикла for-each, он дает ConcurrentModificationException. Есть ли обходной путь?


person aps    schedule 05.08.2011    source источник


Ответы (4)


Используйте Iterator#remove.

Это единственный безопасный способ изменить коллекцию во время итерации. Для получения дополнительной информации см. Руководство по интерфейсу коллекции.

Если вам также нужна возможность добавлять элементы во время итерации, используйте _ 2_.

person mre    schedule 05.08.2011
comment
Итак, я просто создаю объект-итератор этой коллекции, просматриваю коллекцию с помощью hasNext () и удаляю, используя то, что вы предложили? Спасибо. Могу я также добавить элементы? - person aps; 05.08.2011
comment
@aps, нет нельзя добавлять элементы. И да, получить итератор из коллекции. - person mre; 05.08.2011
comment
Добавление нового элемента в цикл while с помощью listIterator.next () и listIterator.add () проверяется только тогда, когда оба 'listIterator' являются одним и тем же объектом. - person jean; 10.01.2012

Один из способов решения проблемы - сохранить изменения и добавить / удалить их после цикла.

Например:

List<Item> toRemove = new LinkedList<Item>();

for(Item it:items){
    if(remove){
        toRemove.add(it);
    }
}
items.removeAll(toRemove);
person jzd    schedule 05.08.2011
comment
спасибо.Я думал об этом раньше. Но у меня довольно много коллекций, поэтому мне придется создавать множество повторяющихся коллекций toRemove для каждой коллекции, которая у меня есть. - person aps; 05.08.2011

Второй обходной путь - использовать класс коллекции, итераторы которого не выдадут исключение. Например, ConcurrentLinkedQueue, _ 2_ и так далее.

Это позволяет избежать необходимости генерировать исключения, предоставляя более слабые модели согласованности для итераторов. (Конечно, вам необходимо понять эти модели и решить, подходят ли они для вашего приложения.)

Обычно они немного медленнее, чем непараллельные коллекции, но быстрее, чем оболочки синхронизированных коллекций, если существует значительная конкуренция.

person Stephen C    schedule 05.08.2011
comment
не могли бы вы уточнить? Я сейчас использую LinkedList? Будет ли использование ConcurrentLinkedList причиной каких-либо недостатков, таких как низкая производительность или что-то еще. И почему не делает исключений? Изменения обрабатываются самим списком? - person aps; 05.08.2011
comment
Вам нужно прочитать javadocs, чтобы понять свойства класса. (Извините, я неправильно прочитал название класса ...) - person Stephen C; 05.08.2011

Если вы просто хотите удалить элемент из коллекции, вы можете использовать Iterator вместо Iterable.

В противном случае вы можете не перебирать исходную коллекцию, а сначала сделать копию списка. Например, если ваша коллекция представляет собой список, вы можете создать новый список ArrayList (originaList) и перебрать его. Модификацию следует внести в исходный список.

Другой альтернативой, которая может быть лучше для вашего варианта использования, является использование не for-each, а традиционного for-.

person nanda    schedule 05.08.2011