Как изменить коллекцию во время итерации с использованием цикла for-each без ConcurrentModificationException? [дубликат]


На этот вопрос уже есть ответ здесь:

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

4 19

4 ответа:

Использование Iterator#remove.

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

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

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

Например:

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

for(Item it:items){
    if(remove){
        toRemove.add(it);
    }
}
items.removeAll(toRemove);

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

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

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

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

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

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