在ArrayList中的Iterator遍历中使用list进行删除操作,却不会产生异常?

按理,应该会抛出 ConcurrentModificationException异常 ,但却能正常运行,代码和结果如下: [图片]
关注者
54
被浏览
17,657
登录后你可以
不限量看优质回答私信答主深度交流精彩内容一键收藏

为什么没抛异常,跟下代码其实就一清二楚了。

ArralyList有个版本号modCount,每次修改ArrayList时版本号就会往上加。Iterator里面也有个版本号expectedModCount它的初始值就是modCount。只有expectedModCount != modCount才会抛异常。所以printList里面的绝对不会抛异常。那问题就出在进行remove的那个迭代器上,首先迭代器是在什么时候比较这两个值呢? 答案是在remove跟next的时候,也就是说hasNext它不会抛出这个异常。

public E next() { checkForComodification(); int i = cursor; if (i >= size) throw new NoSuchElementException(); Object[] elementData = ArrayList.this.elementData; if (i >= elementData.length) throw new ConcurrentModificationException(); cursor = i + 1; return (E) elementData[lastRet = i]; } 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(); } }

然后,看下题主的这段代码

Iterator<Integer> iterator = list.iterator(); while(iterator.hasNext()){ Integer integer = iterator.next(); if(integer == 2) list.remove(integer); }

这里面调用了List的remove方法,所以它不会抛出ConcurrentModificationException。问题是remove之后为什么hasNext会返回false。我们看下hasNext方法

int cursor; // index of next element to return public boolean hasNext() { return cursor != size; }

看注释,cursor是指向一个元素的,也就是当list.remove(integer=2)的时候,cursor实际等于2。而list.remove(integer)后size=3-1=2,所以hasNext返回false,也就不会执行next方法,所以也就不会抛出ConcurrentModificationException。

不过,这个问题,更有意思的ArrayList有两个remove方法

public E remove(int index) boolean remove(Object o)

当参数是Integer时会调用哪个? 我在JLS中找到这么一段,意思是选择重载函数时不会优先考虑装箱跟拆箱

The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.