Java列表的.remove方法仅适用于每个循环内部的倒数第二个对象 [英] Java list's .remove method works only for second last object inside for each loop
问题描述
列表< 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); //删除列表中的第二个工作正常
code
但是,如果我尝试删除列表中的倒数第二,我得到ConcurrentModificationException。在阅读Oracle Certified Associate Java SE 7程序员学习指南2012的时候,我不得不注意到.remove()总是以删除列表中的倒数第二个为例。
<在列表中,添加或删除被视为修改。在你的情况下,你已经做了
5的修改(增加)。
'for each'循环的作用如下,
1.它得到迭代器。
2.检查hasNext()。
public boolean hasNext )
{
return cursor!= size(); //光标初始为零。
lock $
3.如果是true,则获取下一个元素使用next()。
public E next()
{
checkForComodification();
尝试{
E next = get(cursor);
lastRet = cursor ++;
下一个返回;
} catch(IndexOutOfBoundsException e){
checkForComodification();
抛出新的NoSuchElementException();
最终无效checkForComodification()
{
//最初modCount = expectedModCount(我们的情况5)
if(modCount != expectedModCount)
抛出新的ConcurrentModificationException();
$ b 重复步骤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。 b
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屋!