ConcurrentModificationException для ArrayList
У меня есть следующий фрагмент кода:
private String toString(List<DrugStrength> aDrugStrengthList) {
StringBuilder str = new StringBuilder();
for (DrugStrength aDrugStrength : aDrugStrengthList) {
if (!aDrugStrength.isValidDrugDescription()) {
aDrugStrengthList.remove(aDrugStrength);
}
}
str.append(aDrugStrengthList);
if (str.indexOf("]") != -1) {
str.insert(str.lastIndexOf("]"), "\n " );
}
return str.toString();
}
Когда я пытаюсь запустить его, я получаю ConcurrentModificationException
, может ли кто-нибудь объяснить, почему это происходит, даже если код работает в одном потоке? И как я мог избежать этого?
Ответы
Ответ 1
Вы не можете удалить из списка, если вы просматриваете его с циклом "для каждого". Вы можете использовать Iterator
. Заменить:
for (DrugStrength aDrugStrength : aDrugStrengthList) {
if (!aDrugStrength.isValidDrugDescription()) {
aDrugStrengthList.remove(aDrugStrength);
}
}
С
for (Iterator<DrugStrength> it = aDrugStrengthList.iterator(); it.hasNext(); ) {
DrugStrength aDrugStrength = it.next();
if (!aDrugStrength.isValidDrugDescription()) {
it.remove();
}
}
Ответ 2
Как и другие ответы, вы не можете удалить элемент из коллекции, которую вы перебираете. Вы можете обойти это, явно используя Iterator
и удалив там элемент.
Iterator<Item> iter = list.iterator();
while(iter.hasNext()) {
Item blah = iter.next();
if(...) {
iter.remove(); // Removes the 'current' item
}
}
Ответ 3
Мне нравится обратный порядок для цикла, например:
int size = list.size();
for (int i = size - 1; i >= 0; i--) {
if(remove){
list.remove(i);
}
}
поскольку он не требует изучения каких-либо новых структур данных или классов.
Ответ 4
Повторяя цикл, вы пытаетесь изменить значение List в операции remove(). Это приведет к возникновению ConcurrentModificationException.
Следуйте приведенному ниже коду, который достигнет того, что вы хотите, и все же не будет генерировать никаких исключений.
private String toString(List aDrugStrengthList) {
StringBuilder str = new StringBuilder();
List removalList = new ArrayList();
for (DrugStrength aDrugStrength : aDrugStrengthList) {
if (!aDrugStrength.isValidDrugDescription()) {
removalList.add(aDrugStrength);
}
}
aDrugStrengthList.removeAll(removalList);
str.append(aDrugStrengthList);
if (str.indexOf("]") != -1) {
str.insert(str.lastIndexOf("]"), "\n " );
}
return str.toString();
}
Ответ 5
должна существовать параллельная реализация интерфейса List, поддерживающая такую операцию.
попробуйте java.util.concurrent.CopyOnWriteArrayList.class
Ответ 6
Мы можем использовать параллельные классы коллекций, чтобы избежать ConcurrentModificationException, итерации по коллекции, например CopyOnWriteArrayList, вместо ArrayList.
Отметьте этот пост для ConcurrentHashMap
http://www.journaldev.com/122/hashmap-vs-concurrenthashmap-%E2%80%93-example-and-exploring-iterator