Как изменить коллекцию во время итерации с использованием цикла for-each без ConcurrentModificationException? [дубликат]
На этот вопрос уже есть ответ здесь:
Если я изменяю коллекцию, повторяя ее с помощью цикла for-each, это дает ConcurrentModificationException
. Есть ли обходной путь?
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) и повторить его. Необходимо внести изменения в исходный список.
Еще одна альтернатива, которая, возможно, лучше для вашего случая использования, не использовать для-каждого, но традиционный для ...