我正在使用以下代码测试ConcurrentModificationException
集合:
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
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);
}
我不明白为什么要删除&#34; b&#34;没问题,但其他人呢?
答案 0 :(得分:7)
首先要知道的是(如JLS中所述)以下增强的for循环:
for (String s : list) {
// Do something with s
}
相当于:
for (Iterator<String> 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()
从列表中删除元素。