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