集合 iterator.remove()方法详解

直接上代码:

public class test {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0 ; i < 10 ; i++ ) {
            list.add(i);
        }
        Iterator<Integer> iterator = list.iterator();
        int i = 0 ;
        while(iterator.hasNext()) {

            if (i == 3) {
                iterator.remove(); //报java.lang.IllegalStateException异常
            }
            i ++;
        }
        System.out.println(list);
    }
}

为什么会报异常呢,通过一些查资料或者基础较好的读者知道只需要使用调用迭代器iterator.next()方法即可返回当前元素,所以只需要在remove()方法前面加上

iterator.next();

注意这里有人会使用int x = iterator.next();这样来把当前的索引赋值然后再进行操作,其实这样是没必要的,我们来根据这个例子深入的了解一下iterator的源码是如何实现的。

首先我们调用的是list.iterator()方法来获取这个迭代器,当然list类并没有实现这个方法,我们最终是使用它的子类ArrayList来获取迭代器:

/**
     * Returns an iterator over the elements in this list in proper sequence.
     *
     * <p>The returned iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new Itr();
    }

    /**
     * An optimized version of AbstractList.Itr
     */
    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
        int expectedModCount = modCount;

        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        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();
            }
        }

可以看到,iterator()方法返回了一个Itr对象,接着下面,Itr是一个内部类,并且实现了Itertor接口。

回到我们最初的问题,为什么在迭代器中不用在不使用next()方法情况下进行remove操作会出错?我们来看下remove()方法源码,

在remove方法第一行,即可看到:

  if (lastRet < 0)
                throw new IllegalStateException();

当lastRet < 0的情况下,会抛出IllegalStateException异常,那么这个lastRet是什么呢,其实在Itr类就定义了这个lastRet变量,和它一起的还有cursor,expectedModCount;

  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
        int expectedModCount = modCount;

 通过注释可以看到,lastRet就是上个元素的索引,默认是-1,所以直接调用迭代器的remove()方法会报错就是这个原因,

所以在上面的next()方法里,我们可以看到这样的代码:

            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];

它会把cursor游标赋值给i,然后进行+1操作,最后将lastRet赋值成i,所以lastRet就不是默认的-1了,而是会得到上个元素的索引,

所以综合上述的结论:

在使用迭代器iterator.remove()方法前,一定先调用next()方法来给变量lastRet进行赋值操作;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值