Getting a ConcurrentModificationException thrown when removing an element from a java.util.List during list iteration?
1 2 3 4 5 6 7 8 9 10 11 12 13 |
运行此代码时,将抛出ConcurrentModificationException。
当我从列表中删除指定的元素时,列表似乎不知道其大小已更改。
我想知道这是否是集合和移除元素的常见问题?
我相信这是迭代器.remove()方法背后的目的,以便能够在迭代时从集合中移除元素。
例如:
1 2 3 4 5 | Iterator<String> iter = li.iterator(); while(iter.hasNext()){ if(iter.next().equalsIgnoreCase("str3")) iter.remove(); } |
Java 8从Iterator中删除列表的方法是:
1 | li.removeIf([cc lang="java"]) |
即
1 2 3 | List<String> li = new ArrayList<String>(); // ... li.removeIf(st -> !st.equalsIgnoreCase("str3")); |
Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will thow this exception
摘自http://download.oracle.com/javase/1.4.2/docs/api/java/util/concurrentmodificationexception.html
是的,人们会碰到它——问题是在迭代列表时不能修改它。我过去使用过两种选择:
这些选项假定您必须遍历列表以查找要删除的元素——在列表元素是具有您可能测试的属性的复杂对象的情况下非常有用。
在您的特定情况下,您甚至不需要迭代,因为您只需要使用removeall。看看这里的API。还有一些漂亮的方法,如retinallal,可以丢弃论点中没有的所有内容。只要列表中的对象正确实现equals和hashcode,就可以使用remove/retain-like方法。如果您不能依赖equals/hashcode来标识应用程序中实例之间的相等性,则必须自己进行删除….
尝试这个(Java 8):
1 | list.removeIf(condition); |
您可以为每个循环直接创建一个要从中删除元素的列表的副本。对我来说,这是最简单的方法。像这样:
1 2 3 |
希望能帮到你……
我认为值得一提的是Java 8版本。
1 2 3 4 5 6 7 8 9 10 11 | @Test public void testListCur() { List<String> li = new ArrayList<String>(); for (int i = 0; i < 10; i++) { li.add("str" + i); } li = li.stream().filter(st -> !st.equalsIgnoreCase("str3")).collect(Collectors.toList()); System.out.println(li); } |
arraylist具有字段
当调用方法
1 | li.remove("str3"); |
如果是假的话,就把它扔出去。
因此,如果您得到迭代器,并且在集合修改之后,迭代器被认为是无效的,并且您不能使用它。
我遇到了这个问题,我认为更简单的方法和hvgotcodes给出的第二种方法相同。
Or you can copy all the ones you want to keep into a new list as you iterate, and then discard the old list when done.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
我认为最好的答案来自bigdev.de,但我想在其中添加一些内容(例如,如果从列表中删除该项,可能您希望将其记录到某个位置或其他位置):
1 2 3 4 5 6 7 8 | List<String> list = new ArrayList<>(); list.removeIf(a -> { boolean condition = a.equalsIgnoreCase("some condition"); if(condition) logger.info("Item removed from the list:" + a); return condition; }); |
我以不同的方式循环…
1 2 3 4 5 6 7 8 9 10 11 12 | public void testListCur(){ List<String> li=new ArrayList<String>(); for(int i=0;i<10;i++){ li.add("str"+i); } for(int i=0; i<li.size(); i++) if(li.get(i).equalsIgnoreCase("str3")) li.remove(i--); System.out.println(li); } |