【JDK1.8源码剖析】外部迭代器Iterator接口

Iterator源码剖析

(一)简介

Iterabtor是从jdk1.2就存在的接口,称为外部迭代器。支持对容器中的元素进行遍历和移除,还支持流式遍历

外部迭代器的特点是:可拔插。其迭代行为可以挂载到待比较对象的外部, 此外,外部迭代器往往用来支撑内部迭代器的实现。

注意区别于内部迭代器Iterable和枚举器Enumeration

外部迭代器的设计背后体现着迭代器设计模式的思想

(二)源码分析

该接口就只有四种方法
在这里插入图片描述

    // 是否存在未遍历元素
    boolean hasNext();
    // 返回下一个元素
    E next();
    // 移除一个元素
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }
    // 流式遍历。遍历每个元素,并对其执行相应的择取操作
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while(hasNext()) {
            action.accept(next());
        }
    }

Consumer为一个函数式接口,择取从这里实现。Lambda表达式参考【Java 8 in Action】Lambda表达式

我们看一下外部迭代器是如何实现自己的作用的。

我们切到AbstractList抽象类。很容易发现存在Itr类实现了外部迭代器的接口

// 获取类的迭代器
public Iterator<E> iterator() {
        return new Itr();
}
// 修改的次数--集合的增删改查;都能引起modCount数值加1的操作
protected transient int modCount = 0;

private class Itr implements Iterator<E> {
        
        // 下一个元素的索引
        int cursor = 0;

        // 当前元素的索引,该索引的元素被删除了,则置为-1.
        int lastRet = -1;

		// 预期修改的次数
        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();
            }
        }

		// 这个方法体现的是Fail-Fast机制。
		// expectedModCount预期修改的次数,modCount就是实际修改的次数;
		// 在迭代器中,首先定义了一个expectedModCount=modCount默认值是0;这样通过上面的checkForComodification()方法就可以判断list集合在迭代过程中是否被其他线程修改过,这里的修改就是集合的增删改查;因为这些操作都能引起modCount数值加1的操作,这样就使得迭代失败了。
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

ArrayList继承了AbstractList抽象类。知晓源码之后,我们再使用迭代器的API,一切都是那么自然。

    public static void main(String[] args) {
        
        ArrayList<String>  name= new ArrayList<>();
        name.add("zhangsan");
        name.add("lisi");
        name.add("wangwu");
        name.add("zhaoliu");
        Iterator<String> it=name.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
    }

在这里插入图片描述

还有,checkForComodification方法,体现的是Fail-Fast机制(面试会问)。也说明了为什么外部迭代器遍历的时候,如果对集合进行操作,会抛出ConcurrentModificationException异常了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章