我们都知道,java中的ArrayList在使用增强for循环或iterator循环中调用list本身的remove方法删除元素时会报ConcurrentModificationException异常,通过iterator的remove方法来删除就不会报异常了。当然增强for循环只是个语法糖,本质还是用的iterator。今天想试验一下这个异常,于是写了如下代码。
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("abc");
list.add("123");
System.out.println(list);
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String next = iterator.next();
list.remove(next);
}
System.out.println(list);
}
结果输出如下,并没有报错,这就奇怪了,不是说在循环中调用list的remove方法会异常吗,为什么没有呢?如果我把list的元素个数改成3个,就会报异常了,原因的话看一下源码就知道了。
导致这个现象的原因和hasNext()方法有关系,看一下hasNext()源码,cursor是当前遍历到的元素下标,每当我们调用iterator.next()方法时,这个cursor就会加1,当cursor的大小和list中的size一样时,说明遍历到数组尾部了,就没有元素了,hasNext()就会返回false。
接下来分析我们上面的程序,循环开始前,cursor=0,不等于size的大小2,进入循环,调用next()方法,调用next()方法时会调用checkForComodification(),也就是判断一下在循环过程中list是否被改变过,由于我们第一次循环,还没有对list做过改变,所以next可以正常返回。返回下标0处的"abc",此时cursor被置为了1,再调用remove方法,此时list中就只有“123”这个元素了,size为1。
再次循环,由于此时cursor为1,我们remove了一个元素后,list的size也变为了1,所以hasNext()判断为false了,就跳出循环了,然后程序结束。
也就是说,虽然我们list中有两个元素,但是实际上for循环只进行了一次,只把“abc”元素给删除了。所以会出现上面的现象。
如果list中的元素是1个,3个或更多,则会报ConcurrentModificationException异常。所以平时还是不要用这种方式删除list中的元素。