在使用循环语句或者forEach对一个正在遍历的集合进行更新操作时,会导致一个异常java.util.ConcurrentModificationException
出现
Collection<String> c = new ArrayList<>(); c.add("softeem"); c.add("admin"); c.add("lily"); c.add("lucy"); c.add("lilei"); //语法糖 for (String s : c) { System.out.println(s); if(Objects.equals("admin",s)){ c.remove(s); //ConcurrentModificationException } }
java中不允许在对集合遍历时同时进行更新(删除,添加)操作,会导致集合遍历的混乱,同时抛出
但是我们在使用集合对象的remove方法删除倒数第二个元素,不报并发修改异常?
Collection<String> c = new ArrayList<>();
c.add("jack");
c.add("rose");
c.add("sda");
c.add("hai");
for (String s : c) {
if (Objects.equals("sda", s)) {
c.remove(s);
System.out.println(c);
}
具体原因是:
删除倒数第二个元素的时候,cursor指向最后一个元素的,而此时删掉了倒数第二个元素后,cursor和size()正好相等了,所以hasNext()返回false,遍历结束,这样就成功的删除了倒数第二个元素了。
总结并发修改异常出现的原因:
在使用
forEach
(迭代器)循环的前提下对集合进行了更新(添加,删除)操作,每次操作都会有一个修改次数的统计
如果在遍历的同时执行以上操作,将会导致预期的结构修改次数和实际修改次数不一致,抛出并发修改异常
针对并发修改异常的解决方案:
-
在循环遍历时,只记录需要删除的元素位置,或缓存元素对象到新集合中(删除多个),在循环结束后再调用
remove或removeAll()
移除元素String cache = null; for(String s:list){ if(Objects.equals(s,"admin")){ cache=s; } } list.remove(cache);//remove(Object obj); int cache2 = -1; for(int i=0;i<list.size();i++){ if(Objects.equals("admin",list.get(i))){ cache2 = i; } } list.remove(cache2); //remove(int i)
-
直接使用迭代器自身的remove方法:
//获取当前集合的迭代器对象 Iterator<String> it = c.iterator(); while(it.hasNext()){ String s = it.next(); if(Objects.equals(s,"admin")){ it.remove(); } }