在了解ArrayList的遍历之前,先来了解一下for是如何循环一个Iterable对象的。
for循环的内部原理
并发修改异常
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
for (Integer t : list) {
if (t.equals(3)) {
list.remove(t);
}
}
}
执行上面的代码,会抛出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)
....
为什么会产生并发修改异常?
要从ArrayList的实现追踪,List 的remove方法最终会调用 fastRemove,以下是fastRemove的实现:
fastRemove
可以看到方法中会对modCount进行++操作,modCount值改变了会带来什么后果呢?
因为是在遍历,因此最终会取集合类的下一条记录,针对List 会调用next()方法。
再跟到checkForComodification()里:
checkForComodification原来在这,遍历的过程中并没有改变expectedModCount,而改变了modCount,故会抛出并发修改异常。
删除倒数第二个元素
如果把上面的代码改成下面这样:
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
for (Integer t : list) {
if (t.equals(2)) {
list.remove(t);
}
}
}
程序竟然没有抛ConcurrentModificationException,正常结束了,为什么?
原来在每次取下一个元素之前,会先调用hasNext方法,判断是否还要继续遍历,如果为false就不循环了。
因为删除2的时候,会更新size为2。在下一次循环的时候,cursor = 2,size = 2,就结束循环了。
网友评论