Java 在计数循环vs迭代器中从列表中删除元素

Java 在计数循环vs迭代器中从列表中删除元素,java,Java,为什么这是合法的: for(int i=0; i < arr.size(); i++) { arr.remove(i); } 在每个人都开始赶时髦告诉我使用iterator.remove()之前

为什么这是合法的:

for(int i=0; i < arr.size(); i++) {
    arr.remove(i);
}
  • 在每个人都开始赶时髦告诉我使用
    iterator.remove()之前
    
    查看您的代码,我假设arr是一个列表。在顶部循环中,您直接在列表上操作,并在检查时在顶部“重新校准”您的状态

    i < arr.size()
    
    i
    所以,如果你删除一个元素,我必须比较一个较小的值。 另一方面,在第二种情况下,您在实例化迭代器后对集合进行操作,并且不需要重新校准自己


    希望这有帮助。

    在第一个示例中,您正在修改一个数组,该数组没有用作for循环的迭代器


    在第二个示例中,您试图访问一个数组,该数组在循环中使用它进行迭代的同时正在被修改。这就是为什么它抛出
    ConcurrentModificationException

    让我们看看如何实现,例如
    ArrayList
    的迭代器:

    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
    
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size) throw new NoSuchElementException();
            // ...
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }
    
        public void remove() {
            // ...
            ArrayList.this.remove(lastRet);
            // ...
            cursor = lastRet;
            lastRet = -1;
        }
    
    我们删除第一个元素

    list.remove(0);
    
    如果我们现在要调用
    it.remove()
    ,迭代器将删除数字2,因为这是字段
    lastRet
    指向的

    if (item == 1) {
       it.remove(); // list contains 3, 4
    }
    
    这是不正确的行为!迭代器的契约声明,
    remove()
    删除
    next()
    返回的最后一个元素,但在存在并发修改的情况下,迭代器无法保持契约。因此,它选择安全一点并抛出异常

    对于其他收藏而言,情况可能更为复杂。如果修改
    哈希映射
    ,它可能会根据需要增长或收缩。在那个时候,元素将落在不同的存储桶中,在重新灰化之前保持指针指向存储桶的迭代器将完全丢失


    请注意,
    iterator.remove()
    本身不会引发异常,因为它能够更新自身和集合的内部状态。但是,在同一实例集合的两个迭代器上调用
    remove()
    ,会引发错误,因为这会使其中一个迭代器处于不一致的状态。

    对向下投票人说:请不要只对答案进行向下投票,请解释你认为它错了什么。我会非常感激的。真的,对于那些下层选民,请告诉我这有什么错,或者你认为我应该改变什么。如果我错了,请纠正我。我很好奇。
    list.remove(0);
    
    if (item == 1) {
       it.remove(); // list contains 3, 4
    }