Iterator迭代删除的注意事项

本文详细介绍了Java中的Iterator接口及其在ArrayList中的实现方式。解释了Iterator如何通过内部类Itr实现对集合元素的安全遍历,并展示了如何使用Iterator进行元素的删除操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Iterator介绍

Iterator 用同一种逻辑来遍历集合。使得客户端自身不需要来维护集合的内部结构,所有的内部状态都由Iterator来维护。客户端从不直接和集合类打交道,它总是控制Iterator,向它发送"向前","向后","取当前元素"的命令,就可以间接遍历整个集合。
在Java中Iterator为一个接口,它只提供了迭代了基本规则,在JDK中他是这样定义的:对 collection 进行迭代的迭代器。
接口定义为:
public interface Iterator{
     boolean hasNext();
     Object next(); 
     void remove();
}

 其中:

        Object next():返回迭代器刚越过的元素的引用,返回值是Object,需要强制转换成自己需要的类型

        boolean hasNext():判断容器内是否还有可供访问的元素

        void remove():删除迭代器刚越过的元素

2、ArrayList的Iterator实现。

   在 ArrayList 内部首先是定义一个内部类 Itr,该内部类实现 Iterator 接口,如下:
private class Itr implements Iterator<E> {
  //....
}
在内部类实现了Iterator接口,而ArrayList的Iterator是返回的它的内部类Itr,所以我们主要看看Itr是如何实现的。
public Iterator<E> iterator() {
  return new Itr();
}

private class Itr implements Iterator<E> {
    int cursor;       // 下一个元素的索引位置
    int lastRet = -1// 上一个元素的索引位置; -1 if no such
    int expectedModCount = modCount;  //修改的次数      modCount,记录了ArrayList结构性变化的次数

    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();
        }
    }
final void checkForComodification() {
    if (expectedModCount != ArrayList.this.modCount)
        throw new ConcurrentModificationException();
}
}

1、expectedModCount的初值为modCount

2、hasNext的判断条件为cursor!=size,就是当前迭代的位置不是数组的最大容量值就返回true

3、next和remove操作之前都会先调用checkForComodification来检查expectedModCount和modCount是否相等

  如果没checkForComodification去检查expectedModCount与modCount相等,这个程序肯定会报ArrayIndexOutOfBoundsException


3 测试Iterator

public static void main(String[] args) {
    List<String> stringList= new ArrayList<String>();
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");
    stringList.add("d");
    Iterator<String> it = stringList.iterator();
    while(it.hasNext()){
        String str = it.next();
        if(str.contains("c")){
               stringList.remove(str);
        }else {
          logger.info("str:==========={}",str);
       }
    }
}
输出结果为:
str:===========a
str:===========b
d并没有输出, 因为在删除 c 的时候cursor为3,size也变成了3。所以hasNext就返回为false了,循环结束,从而后面的元素也不会输出了.
将stringList.remove(str); 改为 it.remove()
输出结果为:
str:===========a
str:===========b
str:===========d 
因为iterator 的remove 方法,在删除当前元素的同时,将 cursor 置为了 2  并且将 expectedModCount  设为  modCount; 维护了索引的一致性,而当前的size=3  所以 hasNext方法返回为true,循环继续,所以将d正常输出了。
整个过程 cursor、lastRet 、expectedModCount、size 的值变化为 (0 -1 4 4 ) ——>(1 0 4  4)输出a ——>  (2  1  4  4)输出b——> (3 2 4 4 )删除c ——>(2 -1  5  3 )——>(3 2 5 3 )输出d——>cursor=size 循环结束



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值