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