异常分析相信写过一些java代码的人都遇到过这个异常,一般都是由以下代码引起的:
import java.util.list;
import java.util.arraylist;
public class test{
public static void main(string[] args){
list<string> list = new arraylist<>();
list.add(123);
list.add(456);
list.add(789);
for(string obj : list){
list.remove(obj);
}
}
}
上述代码最终会引发java.util.concurrentmodificationexception,那么为什么呢?首先我们将上述代码反编译,得到如下结果(如果对foreach语法糖比较了解可以忽略):
public class test {
public test();
code:
0: aload_0
1: invokespecial #1 // method java/lang/object.<init>:()v
4: return
linenumbertable:
line 4: 0
public static void main(java.lang.string[]);
code:
0: new #2 // class java/util/arraylist
3: dup
4: invokespecial #3 // method java/util/arraylist.<init>:()v
7: astore_1
8: aload_1
9: ldc #4 // string 123
11: invokeinterface #5, 2 // interfacemethod java/util/list.add:(ljava/lang/object;)z
16: pop
17: aload_1
18: ldc #6 // string 456
20: invokeinterface #5, 2 // interfacemethod java/util/list.add:(ljava/lang/object;)z
25: pop
26: aload_1
27: ldc #7 // string 789
29: invokeinterface #5, 2 // interfacemethod java/util/list.add:(ljava/lang/object;)z
34: pop
35: aload_1
36: invokeinterface #8, 1 // interfacemethod java/util/list.iterator:()ljava/util/iterator;
41: astore_2
42: aload_2
43: invokeinterface #9, 1 // interfacemethod java/util/iterator.hasnext:()z
48: ifeq 72
51: aload_2
52: invokeinterface #10, 1 // interfacemethod java/util/iterator.next:()ljava/lang/object;
57: checkcast #11 // class java/lang/string
60: astore_3
61: aload_1
62: aload_3
63: invokeinterface #12, 2 // interfacemethod java/util/list.remove:(ljava/lang/object;)z
68: pop
69: goto 42
72: return
linenumbertable:
line 6: 0
line 7: 8
line 8: 17
line 9: 26
line 10: 35
line 11: 61
line 12: 69
line 13: 72
}
将上述代码翻译出来等价于下列代码:
import java.util.list;
import java.util.arraylist;
import java.util.iterator;
public class test{
public static void main(string[] args){
list<string> list = new arraylist<>();
list.add(123);
list.add(456);
list.add(789);
iterator<string> iterator = list.iterator();
while (iterator.hasnext()){
string obj = iterator.next();
list.remove(obj);
}
}
}
然后我们查看iterator.hasnext()源码,可以发现第一行调用了checkforcomodification方法,我们查看这个方法:
final void checkforcomodification() {
if (modcount != expectedmodcount)
throw new concurrentmodificationexception();
}
在modcount != expectedmodcount这个条件成立的时候会抛出concurrentmodificationexception异常,那么这个条件是怎么成立的呢?
1、首先我们查看modcount的来源,可以发现modcount的值等于当前list的size,当调用list.remove方法的时候modcount也会相应的减1;
2、然后我们查看expectedmodcount的来源,可以看到是在构造iterator(这里使用的是arraylist的内部实现)的时候,有一个变量赋值,将modcount 的值赋给了expectedmodcount;
3、最后当我们执行循环调用list.remove方法的时候,modcount改变了但是expectedmodcount并没有改变,当第一次循环结束删除一个数据准 备第二次循环调用iterator.hasnext()方法的时候,checkforcomodification()方法就会抛出异常,因为此时list的modcount已经变为 了2,而expectedmodcount仍然是3,所以会抛出concurrentmodificationexception异常;
解决方法那么如何解决该问题呢?我们查看java.util.arraylist.itr(arraylist中的iterator实现)的源码可以发现,在该迭代器中有一个remove方法可以 删除当前迭代元素,而且会同时修改modcount和expectedmodcount,这样在进行checkforcomodification检查的时候就不会抛出异常了,该remove 方法源码如下:
public void remove() {
if (lastret < 0)
throw new illegalstateexception();
checkforcomodification();
try {
arraylist.this.remove(lastret);
cursor = lastret;
lastret = -1;
expectedmodcount = modcount;
} catch (indexoutofboundsexception ex) {
throw new concurrentmodificationexception();
}
}
其中arraylist.this.remove(lastret);这一行会改变modcount的值,而后边会同步的修改expectedmodcount的值等于modcount的值;
现在修改我们开头的程序如下就可以正常运行了:
import java.util.list;
import java.util.arraylist;
import java.util.iterator;
public class test{
public static void main(string[] args){
list<string> list = new arraylist<>();
list.add(123);
list.add(456);
list.add(789);
iterator<string> iterator = list.iterator();
while (iterator.hasnext()) {
system.out.println(移除: + iterator.next());
iterator.remove();
}
}
}
以上就是java中concurrentmodificationexception异常警告怎么解决的详细内容。