神圣的ConcurrentModificationException数
我正在使用代码bellow测试集合的ConcurrentModificationException
:
public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("a"); list.add("b"); list.add("c"); for (String s : list) { // if (s.equals("a")) { // ConcurrentModificationException! if (s.equals("b")) { // -->> Magic number, NO Exception, Why? // if (s.equals("c")) { // ConcurrentModificationException! list.remove(s); } } System.out.println(list); }
我不明白为什么删除“b”没关系,但其他人NG?
首先要知道的是(如JLS中所述)以下增强的for循环:
for (String s : list) { // Do something with s }
相当于:
for (Iterator it = list.iterator(); it.hasNext();) { String s = it.next(); // Do something with s }
如果你看一下AbstractList
迭代器的实现,你会看到:
-
hasNext()
不检查并发修改,只是检查我们是否在列表的末尾,使用其大小:public boolean hasNext() { return cursor != size(); }
-
next()
完成的第一件事是调用checkForComodification()
以查看在迭代时列表是否被修改:public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
因此,当您迭代并删除列表的倒数第二个元素时,下一条指令将是对hasNext()
的调用,它将返回false
,因为删除一个元素导致列表的大小减少一个,并且您的迭代将停止而不调用next()
并抛出Exception
。
顺便说一下,所有这些只是一个实现细节,你不应该依赖它,因为它可以改变,并使用它it.remove()
在你迭代时从列表中删除一个元素。