集合--迭代器

2018-08-09  本文已影响0人  sjandroid

目录


java主要容器类图(除Map外,因为Map并未实现Collection接口),从图中可以知道Collection接口实现了Iterable接口。
那Iterable是干嘛的呢??

整体类图.jpg

Iterable

说明

该接口是从JDK1.5添加的,目的是 可以通过foreach语句遍历那么实现了该接口的类中的数据元素

方法

iterator()

说明:返回一个迭代器实例。

使用

    private static void test_2(){
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");

        //while循环(显示调用Iterator)
        //Iterator<String> iterator = list.iterator();
        //while(iterator.hasNext()){
        //    System.out.println(iterator.next());
        //}

        //普通for循环(显示调用Iterator)
        //for(Iterator<String> iterator2 = list.iterator(); iterator.hasNext();){
        //    System.out.println(iterator.next());
        //}

        //for-each遍历(隐式调用Iterator)
        //for-each语法内部会调用Collection中的iterator()生成一个迭代器实例。
        //其内部会调用iterator的hasNext()判断是否还有更多元素。调用next()方法,把返回的数据赋值为str。
        for(String str : list){
            System.out.println(str);
        }
    }
    private static void test_1(){
        Test<String> test = new Test<>(new String[]{"Who Are You?", "I am 雷锋."});

        for(String str : test){
            System.out.println(str);
        }
    }

    /**
     * 具体的Iterable实现类
     */
    private static class Test<T> implements Iterable<T>{
        private T[] array;

        public Test(T[] array) {
            this.array = array;
        }

        @Override
        public Iterator<T> iterator() {
            return new TestIterator<>(array);
        }

        /**
         * 自定义迭代器
         */
        private static class TestIterator<E> implements Iterator<E>{

            private E[] array;
            private int index;

            public TestIterator(E[] array) {
                this.array = array;
            }

            @Override
            public boolean hasNext() {
                return this.index < this.array.length;
            }

            @Override
            public E next() {
                return this.array[this.index++];
            }
        }
    }

log

Who Are You?
I am 雷锋.

接下来看看Iterator是什么,以及它的作用是干嘛的吧。


Iterator

说明

方法:
hasNext():

说明:是否还有更多元素。

next():

说明:如果还有元素的话,则返回下一个元素。

remove():

说明:
1:从底层集合中移除此迭代器返回的最后一个元素。
2:调用此方法之前,需要调用next(),且next()方法调用后只可以调用该方法一次。(多次调用remove()会抛出IllegalStateException)

验证

在调用next()前调用remove()

    private static void test_3(){
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");

        for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){
            iterator.remove();
            System.out.println(iterator.next());
        }
    }

log

Exception in thread "main" java.lang.IllegalStateException
    at java.util.LinkedList$ListItr.remove(LinkedList.java:923)
    at com.iterator.Iterable_Foreach_Test_1.test_3(Iterable_Foreach_Test_1.java:63)
    at com.iterator.Iterable_Foreach_Test_1.main(Iterable_Foreach_Test_1.java:20)

调用next()后,多次调用remove()

    private static void test_3(){
        List<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");

        for(Iterator<String> iterator = list.iterator(); iterator.hasNext();){
            System.out.println(iterator.next());
            iterator.remove();
            iterator.remove();
        }
    }

log

1
Exception in thread "main" java.lang.IllegalStateException
    at java.util.ArrayList$Itr.remove(ArrayList.java:872)
    at com.iterator.Iterable_Foreach_Test_1.test_3(Iterable_Foreach_Test_1.java:65)
    at com.iterator.Iterable_Foreach_Test_1.main(Iterable_Foreach_Test_1.java:20)

通过上述对Iterator的说明基本上在使用的时候做到了心中有数,接下来从源码入手,看一看Iterator的内部实现。


源码分析

ArrayList类结构图.png

接下来我们将从以下几点分析Collection中的迭代器实现。

什么是fail-fast
fail-fast机制介绍:
注意:

AbstractList中的Iteraror实现
    private class Itr implements Iterator<E> {
        /**
         * Index of element to be returned by subsequent call to next.
         * 记录要返回的下一个元素的索引。
         */
        int cursor = 0;

        /**
         * Index of element returned by most recent call to next or
         * previous.  Reset to -1 if this element is deleted by a call
         * to remove.
         * 1:调用previous()后,记录的是此元素之后的一个元素索引。 
         * 2:调用next()后,记录的是此元素之前的一个元素索引。
         * 3:如果调用 remove()删除此元素,则该值重置为-1。
         * 
         * 总结:
         * 1:用于记录当前元素之前或者之后一个元素在列表中的位置。
         * 2:调用next()/previous()后此值才会大于-1。调用remove()后此值被重置为-1。
         */
        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.
         * 1:用于同步AbstractList的modCount属性值。
         * 2:如果检测到该值与AbstractList的modCount值不相等的话则会抛出
         * ConcurrentModificationException。
         */
        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();
            }
        }
        
        //从列表中移除调用next()后新近返回的元素
        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                AbstractList.this.remove(lastRet);
                if (lastRet < cursor)
                    cursor--;
                lastRet = -1;
                expectedModCount = modCount; //调用remove操作List的结构发生了更
改,此时需要同步modCount(remove会使modCount+1代表对列表结构进行了一次
修改)
            } catch (IndexOutOfBoundsException e) {
                throw new ConcurrentModificationException();
            }
        }
        
        //检查AbstractList是否发生了并发操作对AbstractList结构造成了错误的修改。
        //比较Iterator的modCount是否与外部类中的modCount值一致
        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

参考:
https://www.jb51.net/article/92127.htm
https://blog.csdn.net/u011518120/article/details/51932040
http://www.cnblogs.com/skywang12345/p/3308762.html

上一篇下一篇

猜你喜欢

热点阅读