为什么iterator,foreach遍历时不能进行remove操作?
Exception in thread "main" java.util.ConcurrentModificationException 并发修改异常引发的思考!
①list遍历删除元素时会报错,比如下面删除字符串"aa",也有遍历不报错的例子,看下面的例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class TestMain { public static void main(String[] args) { ArrayList<String> array = new ArrayList<String>(); array.add( "cc" ); array.add( "aa" ); array.add( "bb" ); array.add( "aa" ); for (String str : array) { if ( "aa" .equals(str)){ array.remove(str); } } System.out.println(array.size()); } } console: java.util.ConcurrentModificationException |
②下面删除字符串"aa"不会报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class TestMain { public static void main(String[] args) { ArrayList<String> array = new ArrayList<String>(); array.add( "cc" ); array.add( "aa" ); array.add( "bb" ); for (String str : array) { if ( "aa" .equals(str)){ array.remove(str); } } System.out.println(array.size()); } } console : 2 |
③ 索引删除元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class TestMain { public static void main(String[] args) { ArrayList<String> array = new ArrayList<String>(); array.add( "cc" ); array.add( "aa" ); array.add( "bb" ); array.add( "aa" ); for ( int i = 0 ;i < array.size();i++){ if ( "aa" .equals(array.get(i))){ array.remove(i); } } System.out.println(array.size()); } } console: 2 |
④ 迭代器删除元素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public static void main(String[] args) { ArrayList<String> array = new ArrayList<>(); array.add( "cc" ); array.add( "aa" ); array.add( "bb" ); array.add( "ee" ); Iterator<String> iterator = array.iterator(); while (iterator.hasNext()){ String e = iterator.next(); if ( "bb" .equals(e)){ iterator.remove(); } } System.out.println(array.size());}console: 3 |
从上述执行结果可以得出:
① foreach遍历删除后,下一个循环会报错,源码如下红色字体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // remove操作导致modCount++ private void fastRemove(int index) { modCount++; int numMoved = size - index - 1 ; if (numMoved > 0 ) System.arraycopy(elementData, index+ 1 , elementData, index, numMoved); elementData[--size] = null ; // clear to let GC do its work } // 删除元素后,遍历下一个元素会先校验,不通过,报错 public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList. this .elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1 ; return (E) elementData[lastRet = i]; } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } |
② foreach遍历删除后,未报错?
其实原因很简单,因为第二个例子没有走iterator的next方法,删除了字符串"aa"之后,执行hasNext方法返回false直接退出遍历了,hasNext中就是判断cursor != size;此时的cursor是2,而size正好也是2,所以退出了遍历。
③ for循环删除,不会报错,按照索引删除
④ 迭代器的方式遍历,iterator.remove方法删除
总结: 1 foreach遍历,iterator遍历都不能在遍历的过程中使用list.remove或list.add操作,会报并发修改异常,遍历删除后加个break即可解决。
2 iterator遍历过程中如果需要删除可以使用iterator提供的remove()方法。
3 遍历根据元素索引删除是可行的。
以上属于个人心得,不对之处还望大佬指出。
关于http协议
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南