Java 列表的 .remove 方法仅适用于每个循环内部的倒数第二个对象 [英] Java list's .remove method works only for second last object inside for each loop
问题描述
我看到了一种奇怪的行为.
Listli = new ArrayList<>();li.add("a");li.add("b");li.add("c");li.add("d");li.add("e");for(字符串字符串:li){if(str.equalsIgnoreCase("d")){li.remove(str);//删除列表中的倒数第二个工作正常}}
但是,如果我尝试删除列表中倒数第二个以外的任何内容,则会收到 ConcurrentModificationException.我在阅读Oracle Certified Associate Java SE 7 Programmer Study Guide 2012"时引起了我的注意,该指南错误地假设 .remove() 始终与删除列表中倒数第二个的示例一起使用.
在列表中,添加或删除被视为一种修改.在你的情况下,你已经5 修改(添加).
‘for each’循环的工作原理如下,
<块引用>1.获取迭代器.2.检查hasNext().
public boolean hasNext(){返回光标 != size();//游标最初为零.}
<块引用>
3.如果为真,则使用 next() 获取下一个元素.
public E next(){checkForCommodification();尝试 {E next = get(cursor);lastRet = 游标++;接下来返回;} catch (IndexOutOfBoundsException e) {checkForCommodification();抛出新的 NoSuchElementException();}}最终无效 checkForCommodification(){//最初 modCount = expectedModCount(我们的案例 5)如果(modCount!=expectedModCount)抛出新的 ConcurrentModificationException();}
重复第 2 步和第 3 步,直到 hasNext() 返回 false.
如果我们从列表中删除一个元素,它的大小会减少,而 modCount 会增加.
如果我们在迭代时移除一个元素, modCount != expectedModCount 得到满足并抛出 ConcurrentModificationException.
但是删除倒数第二个对象很奇怪.让我们看看它在您的情况下是如何工作的.
最初,
<块引用>cursor = 0 size = 5 --> hasNext() 成功,next() 也成功无一例外.
cursor = 1 size = 5 --> hasNext() 成功,next() 也成功无一例外.
cursor = 2 size = 5 --> hasNext() 成功,next() 也成功无一例外.
cursor = 3 size = 5 --> hasNext() 成功,next() 也成功没有例外.
在您的情况下,当您删除 'd' 时,大小会减少到 4.
<块引用>cursor = 4 size = 4 --> hasNext() 不成功,next() 是跳过.
在其他情况下,ConcurrentModificationException 将作为 modCount != expectedModCount 抛出.
在这种情况下,不会进行此检查.
如果您尝试在迭代时打印元素,则只会打印四个条目.跳过最后一个元素.
希望我说清楚了.
I am seeing a weird behavior.
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
}
}
But if i try to remove any other than second last in the list, i get ConcurrentModificationException. It came to my attention while reading "Oracle Certified Associate Java SE 7 Programmer Study Guide 2012" which incorrectly assumes that .remove() always works with an example of removing the second last in the list.
In a list, adding or removing is considered as a modification. In your case you have made 5 modifications(additions).
‘for each’ loop works as follows,
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();
}
Repeats steps 2 and 3 till hasNext() returns false.
In case if we remove an element from the list , it’s size gets reduced and modCount is increased.
If we remove an element while iterating, modCount != expectedModCount get satisfied and ConcurrentModificationException is thrown.
But removal of second last object is weird. Lets see how it works in your case.
Initially,
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.
In your case as you remove ‘d’ , size gets reduced to 4.
cursor = 4 size = 4 --> hasNext() does not succeed and next() is skipped.
In other cases, ConcurrentModificationException will be thrown as modCount != expectedModCount.
In this case, this check does not take place.
If you try to print your element while iterating, only four entries will be printed. Last element is skipped.
Hope I made clear.
这篇关于Java 列表的 .remove 方法仅适用于每个循环内部的倒数第二个对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!