ConcurrentModificationException的ArrayList中为

问题描述:

我有下面的代码: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,任何人都可以解释为什么它会发生,即使代码在同一个线程中运行?我怎么能避免它?

+3

[你应该停止担忧和爱情愚弄。(http://blog.*.com/2010/11/dr-strangedupe-or-how-我学习的到停止令人担忧和爱的重复数据删除/)。 – Will 2011-05-10 20:39:38

+1

对此异常的解释是ArrayList的迭代器是一个快速失败的迭代器;即当它检测到它在同一时间的收集已被修改时它将失败(抛出异常)。与不引发并发修改异常的故障安全迭代器相比(例如,对集合ConcurrentHashMap和CopyOnWriteArrayList) – 2014-05-28 12:05:18

如果您使用“for each”循环浏览它,则不能从列表中删除。您可以使用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(); 
    } 
} 
+0

java的foreach语法实际上使用Iterator,一些IDE会报告这个解决方案,并建议用foreach替换(for(MyListener listener:MyListenerList)) – 2014-12-29 09:42:14

+0

@HugoGresse是的,但这是相反的方向。迭代器公开了对其迭代安全的'remove',这是foreach“失败”的事情。 – 2014-12-30 21:52:31

+2

不知道,谢谢@KonradGarus – 2014-12-31 08:08:14

在遍历循环时,您试图在remove()操作中更改List值。这将导致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(); 
} 
+0

为什么downvote? – bragboy 2010-07-06 09:20:52

+2

'aDrugStrengthList.removeAll(removalList)' – 2010-07-06 09:25:37

+0

@TimBender - 谢谢你编辑了答案。 – bragboy 2016-03-07 14:51:43

像其他的答案说,你不能从你遍历集合中删除的项。您可以通过明确使用Iterator并删除该项目来解决此问题。

Iterator<Item> iter = list.iterator(); 
while(iter.hasNext()) { 
    Item blah = iter.next(); 
    if(...) { 
    iter.remove(); // Removes the 'current' item 
    } 
} 

应该有List接口支持这种操作的同时FPGA实现。

尝试java.util.concurrent.CopyOnWriteArrayList.class

+0

我和HashMap有同样的问题,用Map接口的另一个实现 修正。 你应该自己测试一下。我不知道有关CopyOnWriteArrayList – idiotgenius 2010-07-06 13:35:21

我喜欢反向顺序循环,例如:

int size = list.size(); 
for (int i = size - 1; i >= 0; i--) { 
    if(remove){ 
     list.remove(i); 
    } 
} 

,因为它不需要学习任何新的数据结构或类。

+0

的详细信息,谢谢。我不知道这个窍门。 – 2018-01-30 14:40:21

我们可以使用并发集合类来避免ConcurrentModificationException迭代集合,例如CopyOnWriteArrayList而不是ArrayList。

检查这个职位的ConcurrentHashMap

http://www.journaldev.com/122/hashmap-vs-concurrenthashmap-%E2%80%93-example-and-exploring-iterator