Java 列表的 .remove 方法仅适用于每个循环内部的倒数第二个对象 [英] Java list's .remove method works only for second last object inside for each loop

查看:20
本文介绍了Java 列表的 .remove 方法仅适用于每个循环内部的倒数第二个对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到了一种奇怪的行为.

 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆