为何会发生java.util.ConcurrentModificationException?
来源:互联网 发布:tensorflow gpu配置 编辑:程序博客网 时间:2024/06/11 00:58
相信很多初学的朋友都遇到过这个异常,但是又不知道怎么回事,今天我给大家说一下,通过解读源码来解析这个异常是怎样发生的,我们先写一段代码:
public static void main(String[] args) {List<String> list = new ArrayList<String>();list.add("hello");list.add("world");list.add("!");list.add("extra");for(String str:list){System.out.println(str);list.remove(str);//主要看这里}}这段代码就是遍历集合,然后把集合的元素移除,大家可以看到,这个方法在ArrayList类里面是有的,但是为什么遍历的时候会提示这个异常呢?先看一下异常,异常信息如下:
Exception in thread "main" java.util.ConcurrentModificationExceptionat java.util.ArrayList$Itr.checkForComodification(Unknown Source)at java.util.ArrayList$Itr.next(Unknown Source)at test.ConcurrentModifiedExceptionTest.main(ConcurrentModifiedExceptionTest.java:14)
注意看后面的内部类Itr,说明异常是在Itr这个类抛出来的,奇怪了,明明我们调用的是list的remove方法,为什么和Itr有关呢?其实这个就和java的语法糖有关了,先不说语法糖,我们先看一下Itr这个内部类,然后找到checkForComodification方法,可能你会发现有几个地方定义了,我们要看的是Itr类的方法,如下:
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
非常简单的一个方法,modCount不等于expectedModCount的时候就抛出这个异常了,出错的位置找到了,但是为什么出错似乎还没找到,接着看,因为我们最终需要将java文件编译成class文件,执行的时候也是执行class文件,那么也就是我们写的代码被编译成class文件的时候用到了Itr这个内部类,反编译一下这个类看一下反编译之后的代码是怎样的,可能不同的反编译器会有不同的结果,但是本质上应该是一样的,因为一般是没办法还原语法糖的(或许可以可能是我对jvm了解不够),因为编译的时候语法糖就被去掉了,除非class文件中包含还原语法糖的信息,代码如下:
public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("hello"); list.add("world"); list.add("!"); list.add("extra"); Iterator var3 = list.iterator(); while(var3.hasNext()) { String j = (String)var3.next(); list.remove(j); }
可以看到红色的代码就是我们的源码被编译之后的代码(当然这个是我们反编译之后的,class文件内容是字节码),也就是我们使用foreach语法之后会被编译器进行语法糖解析最终的使用的是iterator的方式进行遍历的,红色代码第一句返回的就是一个Itr类的实例:
public Iterator<E> iterator() { return new Itr(); }关键是最后一句,调用list的remove方法的时候里面有一句modCount++;这句改变了这个值,但是expectedModCount这个值并没有变,所以如果使用foreach的方式进行编码的时候记得要调用iterator的remove方法,否则就会抛异常。可能你写成以下这样了:
Iterator<String> it = list.iterator();while(it.hasNext()){it.remove();}
但是你发现还是会抛异常,只是异常信息不一样了,明明也是调用了iterator的remove方法啊,怎么还是异常?看了源码会发现remove方法的第一句就是判断lastRet是否小于0,初始化就是-1,所以肯定会抛异常,那么应该怎么做?很简单,就调用一下next()方法就ok了。当然一般情况下我们都会调用next方法的,这里只是说明一下。
阅读全文
0 0
- 为何会发生java.util.ConcurrentModificationException?
- 为什么会出现 java.util.ConcurrentModificationException 异常?
- 为什么会出现 java.util.ConcurrentModificationException 异常?
- 为什么会出现 java.util.ConcurrentModificationException 异常?
- 为什么会出现 java.util.ConcurrentModificationException 异常?
- 使用迭代器遍历集合时,当集合中的数据发生变化是会抛出java.util.ConcurrentModificationException异常
- 【ConcurrentModificationException】java.util.ConcurrentModificationException 解决办法
- java.util.ConcurrentModificationException! java.util.ConcurrentModificationException!
- 主题:为什么会出现 java.util.ConcurrentModificationException 异常?
- java:java.util.ConcurrentModificationException
- 异常:java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException异常
- java.util.ConcurrentModificationException异常
- java.util.ConcurrentModificationException 解决办法
- java.util.ConcurrentModificationException 异常
- 异常:java.util.ConcurrentModificationException
- 异常:java.util.ConcurrentModificationException
- java.util.ConcurrentModificationException
- gradle 编译jar包+混淆
- 代码 Openblas 源码架构 和 调用过程
- ODPS数据倾斜导致的问题
- js通过读取外部的txt文件,给html的标签赋值
- Spring Aop 初探(2)
- 为何会发生java.util.ConcurrentModificationException?
- iOS开发——UITableView优化之缓存cell高度
- 【机器学习】Tensorflow概率编程:线性混合模型
- 从 JavaScript 到 TypeScript
- 学习硬解码视频过程(安卓)中参考的一些文档
- 阻止冒泡
- 增强学习简介-基础概念
- Java中static关键字用法总结
- JAVA数据结构之线性表的链式存储结构——单链表