Если я изменяю коллекцию, итерации по ней, используя цикл for-each, она дает ConcurrentModificationException
. Есть ли способ обхода?
Как изменить коллекцию при повторении с использованием for-each цикла без ConcurrentModificationException?
Ответ 1
Используйте Iterator#remove
.
Это единственный безопасный способ изменения коллекции во время итерации. Для получения дополнительной информации см. Учебник по интерфейсу коллекции.
Если вам нужна возможность добавлять элементы во время итерации, используйте ListIterator
.
Ответ 2
Одна работа заключается в том, чтобы сохранить изменения и добавить/удалить их после цикла.
Например:
List<Item> toRemove = new LinkedList<Item>();
for(Item it:items){
if(remove){
toRemove.add(it);
}
}
items.removeAll(toRemove);
Ответ 3
Вторым обходным решением является использование класса коллекции, итераторы которого не будут давать исключение. Например ConcurrentLinkedQueue
, ConcurrentHashMap
и т.д..
Они избегают необходимости исключать исключения, предоставляя более слабые модели согласованности для итераторов. (Конечно, вам нужно понять эти модели и решить, подходят ли они для вашего приложения.)
Они, как правило, немного медленнее, чем неконкурентные коллекции, но быстрее, чем синхронизированные обертки коллекции, если есть серьезные утверждения.
Ответ 4
Если вы просто хотите удалить элемент из коллекции, вы можете использовать Iterator вместо Iterable.
В противном случае вы можете не перебирать исходную коллекцию, а сначала сделать копию списка. Например, если ваша коллекция является списком, вы можете создать новый ArrayList (originaList) и перебрать его. Изменения должны быть внесены в исходный список.
Другая альтернатива, которая может быть лучше для вашего случая использования, не должна использоваться для каждого, но традиционная для -.