美文网首页
Iterator迭代器

Iterator迭代器

作者: kindol | 来源:发表于2018-04-27 21:05 被阅读0次

    Iterator<E>接口

    Iterator<E>接口含有3个方法

    public interface Iterator<E>{
        E next();
        boolean hasNext();
        void remove();
    }
    
    • next()

      如果到达了集合末尾,将会抛出NoSuchElementException,因此,一般调用next()前要调用hasNext()

      然而,跟C++STL的迭代器不同,STL中的迭代器是根据数据索引建模的,道理跟索引i对应a[i]元素一样,而Java迭代器被认为是位于两个元素之间,当调用next时,迭代器就越过下一个元素,并返回越过的元素的引用,有点类似“消费掉”的意思。

    • 删除元素

      删除上次调用next方法时返回的元素,next方法和remove方法的调用互相依赖,如果调用remove之前没有调用next是不合理的,会抛出IllegalStateException(set方法同理)

    ListIterator接口

    相比于Iterator,还包括add,previous,hasPrevious方法,LinkedList类就实现了此接口

    previous,hasPrevious和next,hasNext同,只是一个顺着一个逆着遍历,当然,在调用remove的时候,删除的是越过的元素,而并不是说一定为迭代器左边的元素

    java中的链表都是双向链表,所以会有previous,hasPrevious,add方法仅针对资源有序的集合,也就是说,add方法将会添加到当前的iterator后面,如果iterator刚创建,也就是在头结点前,此时调用add则此新节点将会变成头结点

    对于set等无序集合,在iterator接口是实现add方法就没有意义,所以Collection拓展的是Iterator接口,没有包括add方法

    Collection

    Collection接口拓展了Iterator接口,也就是说所有的

    foreach

    foreach循环可以和任何实现了Iterable接口的对象一起工作,这个接口只有一个方法

    public interface Iterable<E>{
        Iterator<E> iterator();
    }
    

    AbstractList中Iterator的实现

    在iterator接口中返回了一个内部类Itr

    private class Itr implements Iterator<E> {
        //下一个元素的索引位置
        int cursor = 0;
    
        //上一个元素的索引位置,这个值将会变成-1在调用remove()之后
        int lastRet = -1;
    
        /**
         * The modCount value that the iterator believes that the backing
         * List should have.  If this expectation is violated, the iterator
         * has detected concurrent modification.
         */
        int expectedModCount = modCount;
    
        public boolean hasNext() {
            return cursor != size();
        }
    
        public E next() {
            checkForComodification();
            try {
                int i = cursor;
                E next = get(i);
                lastRet = i;
                cursor = i + 1;
                return next;
            } catch (IndexOutOfBoundsException e) {
                checkForComodification();
                throw new NoSuchElementException();
            }
        }
    
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();
    
            try {
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }
    
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }
    

    next()的实现是通过get(cursor)然后cursor++,通过这样实现遍历

    而在remove()中,有这么一句“expectedModCount = modCount”,这是一种称为“快速失败”的机制,提供了迭代过程中集合的安全性,也就是说迭代过程中不允许修改集合

    modCount记录修改此列表的次数:包括改变列表的结构,改变列表的大小,打乱列表的顺序等使正在进行迭代产生错误的结果。

    每次增删操作都有modCount++,通过和expectedModCount的对比,迭代器可以快速的知道迭代过程中是否存在list.add()类似的操作,存在的话快速失败!

    然而,需要注意的是,仅仅设置元素的值并不是结构的修改

    相关文章

      网友评论

          本文标题:Iterator迭代器

          本文链接:https://www.haomeiwen.com/subject/qewilftx.html