public static void main(String[] args) {
List list= new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
for (String s: list) {
if (s.equals("1")) {
list.remove(s);
}
}
System.out.println(list);
}
这是你会觉得没什么问题,逻辑很清晰,然后你就去跑了一下发现一个错误
java.util.ConcurrentModificationException异常了,翻译成中文就是:并发修改异常。
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at shen.callable.XiaoMing.main(Main.java:33)
然后你换成删除2,你发现又可以了,再试下1又报错了,接下来我们就讲讲这是为什么?
我们打开target目录下找到这个文件的字节码文件你会发下它长这个样子去了
public static void main(String[] args) {
List list = new ArrayList();
list.add("1");
list.add("2");
list.add("3");
Iterator var2 = list.iterator();
while(var2.hasNext()) {
String s = (String)var2.next();
if (s.equals("1")) {
list.remove(s);
}
}
}
从中我们可以看到list的增强型循环其实就是采用的iteratior形式,使用的核心方法是hasnext()和next()
(数组当然用不了迭代器就是普通的for循环,感兴趣的可以自己写一个看看)
我们接下来就看下list里的迭代器是如何实现的。
public Iterator iterator() {
return new Itr();
}
很简单,就是new了一个对象而已,那这个对象是什么呢?我们继续点下去。
我们发现就在这个方法的下面,这个Itr是arrayList的一个内部类。
当我们的代码执行到remove语句的时候
我们调用的是属于list的remove方法
这里我们的modCount++了
而当我们再一次循环的时候,调用的是list内部类itr的next方法,我们可以跟进看下
进入checkForComdification()方法
大家可以返回上面的Itr内部类的大致图看下expectedModCount会等于什么,
在我们调用的list的remove的时候,modCount++了,而我们的expectedModCount是等于最开始modCount值
所以这里明显不等于了,条件为真,
throw new ConcurrentModificationException();
其实这条线路不难推断,跟着报错点进去就能发现。
其实究其原因就是因为增强型循环对于list的遍历采用的是迭代器。
我已知的有俩种方法:
1、直接使用最简单的for循环遍历,条件判断一定要用i 2、使用迭代器的remove方法 这里又要插几句了,为什么迭代器的remove反法有用呢?如果细心观察了源码的朋友应该能看到为什么。 今天就说到这吧,最近在忙着找工作,因为只是普通二本的原因,困难重重,面试机会都没有。这就是为什么迭代器的remove起作用的原因。