2013-04-19 2 views
2

Моя программа бросает ConcurrentModificationException, когда я запускаю следующий фрагмент кода. В ходе некоторых исследований я обнаружил, что элемент в списке не может быть добавлен или удален в цикле итератора. Что мне делать сейчас, чтобы удалить элемент в List<Bean>?Почему удаление элемента из списка вызывает ConcurrentModificationException?

for (Iterator<Entry<String, List<Bean>>> iterator = dataMap.entrySet().iterator(); iterator.hasNext();) { 
    Entry<String, List<Bean>> entry = (Entry<String, List<Bean>>)iterator.next(); 
    List<Bean> dateWiseValues = (List<Bean>) entry.getValue(); 
    int j = 0; 
    for (Bean statBean : dateWiseValues) { 
     for (int i = 0; i < commonElements.size(); i++) { 
      if(statBean.getDate().equalsIgnoreCase(commonElements.get(i))) { 
       //remove the bean 
       entry.getValue().remove(j); 
      } 
     } 
     j++; 
    } 
} 
+1

удалите его позже, или вы можете скопировать свои значения в список «зеркало» и перебрать зеркало, удалив их из фактического списка. –

+0

это также может быть интересно: http://docs.oracle.com/javase /1.5.0/docs/api/java/util/concurrent/CopyOnWriteArrayList.html – subarachnid

+0

@Subarachnid, это намного лучше, опубликуйте его как ответ –

ответ

5

Вместо того чтобы использовать диапазон на основе для цикла по dateWiseValues, используйте Iterator явно, так что вы можете вместо этого вызвать Iterator#remove():

for (final Iterator<? extends Bean> it = dateWiseValues.iterator(); 
    it.hasNext();) { 
    final Bean statBean = it.next(); 
    for (int i = 0, last = commonElements.size(); i != last; ++i) 
    if (statBean.getDate().equalsIgnoreCase(commonElements.get(i)))     
     it.remove(); 
} 

В общем, это безопасно удалить элементы и лежащую в основе коллекции, итерации по ней, пока вы делаете это через один из итераторов коллекции.


Хотя мы не можем видеть конкретный тип dateWiseValues, мы знаем, что это подтип List. Двумя распространенными конкретными типами, использующими List, являются ArrayList и LinkedList. Документация прозы на уровне класса для каждого из этих классов содержит следующее предостережение:

Итераторов возвращенного iterator и listIterator методов этого класса является отказоустойчивость быстро: если список конструктивно изменен в любое время после того, как итератор созданный, любым способом, за исключением методов Iterator собственных remove или add, итератор будет выдавать ConcurrentModificationException. Таким образом, перед лицом одновременной модификации итератор быстро и чисто, а не рискует произвольным, недетерминированным поведением в неопределенное время в будущем.

Обратите внимание, что это предупреждение, что вы должны использовать Iterator#remove() для мутации во время итерации, или вы будете сталкиваться заброшенным ConcurrentModificationException в следующий раз, когда вы используете тот же или любой другой итератор ходить за тот же базовый список.

+0

Большое спасибо! Я попробую это сейчас. :) – user1669488

2

Когда вы используете усиленный цикл for, он неявно использует Iterator за кулисами. Это Iterator, выбрасывающий ConcurrentModificationException, а не явный итератор iterator, который вы определили во внешнем цикле for. Вы не можете удалить из списка, а Iterator выполняет итерацию по нему, если вы не вызываете Iterator#remove(), который удаляет текущий элемент списка и избегает ConcurrentModificationException.

Ваши два варианта:

  • Перепишите расширенный for цикл явно использовать while петлю и Iterator, затем вызова remove(), когда вы хотите, чтобы удалить элемент.
  • Создайте List предметов для удаления. Когда вы определите, что хотите удалить , удалите этот элемент, add его элементам для удаления списка. Затем после вы закончили итерацию, позвоните removeAll в первоначальный список, чтобы удалить все предметы, которые вы хотите удалить.
Смежные вопросы