我看到了一个奇怪的行为。
List<String> li = new ArrayList<>();
li.add("a");
li.add("b");
li.add("c");
li.add("d");
li.add("e");
for(String str:li){
if(str.equalsIgnoreCase("d")){
li.remove(str); //removing second last in list works fine
}
}
但是如果我尝试删除列表中倒数第二个以外的任何内容,我会得到 ConcurrentModificationException。在阅读“Oracle Certified Associate Java SE 7 Programmer Study Guide 2012”时引起了我的注意,该指南错误地假设 .remove() 始终适用于删除列表中倒数第二个的示例。
在列表中,添加或删除被视为修改。在你的情况下你做了
5 修改(增加)。
“for each”循环的工作方式如下,
1.It gets the iterator.
2.Checks for hasNext().
public boolean hasNext()
{
return cursor != size(); // cursor is zero initially.
}
3.If true, gets the next element using next().
public E next()
{
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch (IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
final void checkForComodification()
{
// Initially modCount = expectedModCount (our case 5)
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
重复步骤 2 和 3 直到 hasNext() 返回 false。
如果我们从列表中删除一个元素,它的大小会减小,而 modCount 会增加。
如果我们在迭代时删除一个元素,modCount != expectedModCount 得到满足
并抛出 ConcurrentModificationException。
但是移除倒数第二个对象很奇怪。让我们看看它在您的案例中是如何工作的。
最初,
cursor = 0 size = 5 --> hasNext() succeeds and next() also succeeds
without exception.
cursor = 1 size = 5 --> hasNext() succeeds and next() also succeeds
without exception.
cursor = 2 size = 5 --> hasNext() succeeds and next() also succeeds
without exception.
cursor = 3 size = 5 --> hasNext() succeeds and next() also succeeds
without exception.
在您删除“d”的情况下,大小会减小到 4。
cursor = 4 size = 4 --> hasNext() does not succeed and next() is
skipped.
在其他情况下,ConcurrentModificationException 将被抛出为 modCount != expectedModCount。
在这种情况下,不会进行此检查。
如果您尝试在迭代时打印您的元素,则只会打印四个条目。跳过最后一个元素。
希望我说清楚了。