您的位置:首页 > 其它

Iterator迭代删除的注意事项

2018-01-03 16:41 309 查看


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 循环结束
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: