神圣的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()在你迭代时从列表中删除一个元素。