【问题标题】:How Iterator's remove method actually remove an objectIterator 的 remove 方法实际上是如何删除一个对象的
【发布时间】:2013-04-06 06:42:03
【问题描述】:

我们都知道,在迭代时从集合中删除对象的最安全“可能也是唯一安全”的方法是首先检索Iterator,执行循环并在需要时删除;

Iterator iter=Collection.iterator();
while(iter.hasNext()){
    Object o=iter.next()
    if(o.equals(what i'm looking for)){
        iter.remove();
    }
}

我想了解的是,如何执行此删除操作,但遗憾的是还没有找到深入的技术解释,
如果:

for(Object o:myCollection().getObjects()){
    if(o.equals(what i'm looking for)){
        myCollection.remove(o);
    }
}

会抛出ConcurrentModificationException,“从技术上讲”Iterator.remove() 是做什么的?它会移除对象、中断循环并重新开始循环吗?

我在官方文档中看到:

"删除当前元素。抛出IllegalStateException,如果 尝试调用 remove() 之前没有调用 下一个()。”

“删除当前元素”部分让我想到了“常规”循环中发生的完全相同的情况 =>(执行相等测试并在需要时删除),但为什么迭代器循环 ConcurrentModification 安全?

【问题讨论】:

标签: java loops collections iterator


【解决方案1】:

在迭代列表时不能修改列表的原因是因为迭代器必须知道 hasNext() 和 next() 返回什么。

具体实现方式取决于具体实现,但您可以查看 ArrayList/AbstractList/LinkedList 等的源代码。

另请注意,在某些情况下,您可以使用类似这样的代码作为替代:

List<Foo> copyList = new ArrayList<>(origList);
for (Foo foo : copyList){
  if (condition){
    origList.remove(foo);
  }
}

但此代码可能会运行得稍微慢一些,因为必须复制集合(仅限浅复制)并且必须搜索要删除的元素。

另外请注意,如果您直接使用迭代器,建议使用 for 循环而不是 while 循环,因为这会限制变量的范围:

for (Iterator<Foo> iterator = myCollection.iterator(); iterator.hasNext();){
...
}

【讨论】:

    【解决方案2】:

    Iterator 移除元素的具体方式取决于其实现,对于不同的 Collection,这可能会有所不同。绝对不会破坏您所处的循环。我刚刚查看了 ArrayList 迭代器的实现方式,代码如下:

    public void remove() {
        if (lastRet < 0)
            throw new IllegalStateException();
        checkForComodification();
    
        try {
            ArrayList.this.remove(lastRet);
            cursor = lastRet;
            lastRet = -1;
            expectedModCount = modCount;
        } catch (IndexOutOfBoundsException ex) {
            throw new ConcurrentModificationException();
        }
    }
    

    因此它检查并发修改,使用公共 ArrayList remove 方法删除元素,并增加列表修改的计数器,以便在下一次迭代时不会抛出 ConcurrentModificationException。

    【讨论】:

    • 迭代器返回的最后一个元素的索引。它设置为 -1,因为该元素刚刚从列表中删除。
    • 我的 Java 有点生锈了 - 但是ArrayList.this.remove(lastRet) 是什么?为什么要写ArrayList.this?是内部类还是什么?
    • @BenjaminGruenbaum 是的,这条线是从内部类(private class Itr implements Iterator&lt;E&gt;)调用的,所以this指向Itr的实例,ArrayList.this指向ArrayList的实例。
    猜你喜欢
    • 2015-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-19
    • 1970-01-01
    相关资源
    最近更新 更多