如何避免“ConcurrentModificationException”同时从ArrayList中删除元素,而迭代呢?

我试图从ArrayList删除一些元素,而像这样迭代它:

 for (String str : myArrayList) { if (someCondition) { myArrayList.remove(str); } } 

当然,当迭代myArrayList ConcurrentModificationException尝试从列表中删除项目时,我得到了ConcurrentModificationException 。 有没有一些简单的解决scheme来做到这一点?

使用Iterator并调用remove()

 Iterator<String> iter = myArrayList.iterator(); while (iter.hasNext()) { String str = iter.next(); if (someCondition) iter.remove(); } 

作为别人答案的替代,我总是这样做:

 List<String> toRemove = new ArrayList<>(); for (String str : myArrayList) { if (someCondition) { toRemove.add(str); } } myArrayList.removeAll(toRemove); 

这将避免你不得不直接处理迭代器,但需要另一个列表。 无论出于何种原因,我总是喜欢这条路线。

Java 8用户可以这样做: list.removeIf(...)

  List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c")); list.removeIf(e -> (someCondition)); 

它将删除列表中的某些条件满足的元素

你必须使用迭代器的remove()方法,这意味着没有增强的for循环:

 for (final Iterator iterator = myArrayList.iterator(); iterator.hasNext(); ) { iterator.next(); if (someCondition) { iterator.remove(); } } 

不不不!

在单一的threated任务,你不需要使用Iterator,此外,CopyOnWriteArrayList(由于性能命中)。

解决scheme要简单得多: 尝试使用规范for循环而不是for-each循环

根据Java版权所有人(几年前的Sun,现在是Oracle) 的每一个循环指南 ,它使用迭代器遍历集合,并隐藏它,使代码看起来更好。 但不幸的是,正如我们所看到的,它产生了比利润更多的问题,否则这个话题就不会出现。

例如,这个代码在修改的ArrayList上进入下一个迭代时将导致java.util.ConcurrentModificationException:

  // process collection for (SomeClass currElement: testList) { SomeClass founDuplicate = findDuplicates(currElement); if (founDuplicate != null) { uniqueTestList.add(founDuplicate); testList.remove(testList.indexOf(currElement)); } } 

但下面的代码工作得很好:

  // process collection for (int i = 0; i < testList.size(); i++) { SomeClass currElement = testList.get(i); SomeClass founDuplicate = findDuplicates(currElement); if (founDuplicate != null) { uniqueTestList.add(founDuplicate); testList.remove(testList.indexOf(currElement)); i--; //to avoid skipping of shifted element } } 

所以,尝试使用索引方法迭代集合,避免for-each循环,因为它们不是等价的! For-each循环使用一些内部迭代器,它们检查集合修改并抛出ConcurrentModificationExceptionexception。 为了确认这一点,当使用我发布的第一个示例时,仔细查看打印的堆栈跟踪:

 Exception in thread "main" java.util.ConcurrentModificationException at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372) at java.util.AbstractList$Itr.next(AbstractList.java:343) at TestFail.main(TestFail.java:43) 

对于multithreading使用相应的多任务处理(如同步关键字)。

虽然其他build议的解决scheme工作,如果你真的想让解决scheme成为线程安全的,你应该用CopyOnWriteArrayListreplaceArrayList

  //List<String> s = new ArrayList<>(); //Will throw exception List<String> s = new CopyOnWriteArrayList<>(); s.add("B"); Iterator<String> it = s.iterator(); s.add("A"); //Below removes only "B" from List while (it.hasNext()) { s.remove(it.next()); } System.out.println(s); 

如果你想在遍历期间修改你的List,那么你需要使用Iterator 。 然后你可以使用iterator.remove()在遍历期间删除元素。

 List myArrayList = Collections.synchronizedList(new ArrayList()); //add your elements myArrayList.add(); myArrayList.add(); myArrayList.add(); synchronized(myArrayList) { Iterator i = myArrayList.iterator(); while (i.hasNext()){ Object object = i.next(); } } 

一种替代方法是将List转换为array ,迭代它们并根据您的逻辑从List直接删除它们。

 List<String> myList = new ArrayList<String>(); // You can use either list or set myList.add("abc"); myList.add("abcd"); myList.add("abcde"); myList.add("abcdef"); myList.add("abcdefg"); Object[] obj = myList.toArray(); for(Object o:obj) { if(condition) myList.remove(o.toString()); } 

您可以使用迭代器remove()函数从底层集合对象中删除该对象。 但在这种情况下,您可以从列表中删除相同的对象而不是其他任何对象。

从这里