美文网首页
集合--迭代器

集合--迭代器

作者: sjandroid | 来源:发表于2018-08-09 19:31 被阅读0次

目录

  • Iterable
  • Iterator
  • ListIterator
  • Spliterator

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
  • AbstractList中的Iteraror实现
  • ArrayList中的Iterator相较于AbstractList中的Iterator做了哪些优化
什么是fail-fast
fail-fast机制介绍:
  • 说明:
    fail-fast是一种 错误 机制,当检测到 容器 类的结构被进行了 不正确修改之后,则会抛出ConcurrentModificationException。
  • 触发:
    在使用迭代器时对 容器 类中的数据元素遍历,添加,删除,修改时。
  • 作用:
    用于提醒 容器 类的结构被进行了 不正确修改
  • 如何检测(检测依据):
    迭代器中会保存容器类中modCount的一个副本,当利用迭代器进行遍历,添加,删除,修改操作时,会检测迭代器中的modCount与容器类中的modCount值是否一致,如果不一致则会抛出ConcurrentModificationException,此时fail-fast事件就产生了。
注意:
  • modCount:该值是用于记录 AbstractList结构被修改的次数。那么什么操作会引起AbstractList的结构发生改变呢?
  • 具体的例如List的add操作,remove操作等,这些方法都会对List的存储数据的列表大小发生更改。详细请查看 集合--ArrayList--基本方法使用说明 中关于subList()方法的介绍。

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

相关文章

  • 迭代器模式

    一. 什么是迭代器模式 迭代器模式: 用来遍历集合对象 (集合在这里也叫做容器) 迭代器模式, 将对集合的遍历操作...

  • 007-集合,list,set,map

    集合的概念 Collection集合 常用方法 迭代器 迭代器使用 迭代器的问题 泛型 代码演示: ArrayLi...

  • java学习笔记6

    迭代器的原理及源码解析 A:迭代器原理迭代器原理:迭代器是对集合进行遍历,而每一个集合内部的存储结构都是不同的,所...

  • php设计模式——迭代器模式

    迭代器模式 说明 迭代器模式是遍历集合的成熟模式,迭代器模式的关键是将遍历集合的任务交给一个叫做迭代器的对象,它的...

  • Map----entrySet

    Map集合不需要迭代器; 他是先将Map集合转化为Set集合; 然后Set集合调用迭代器进行遍历。 Map.Ent...

  • 设计模式——迭代器模式

    什么是迭代器模式 用迭代器来封装集合对象的遍历细节,使调用者能够通过统一的接口来实现对集合的遍历。 迭代器也给集合...

  • Iterator迭代器

    前言: Java中的Iterator迭代器是为了对集合进行迭代 迭代器的使用:

  • 用迭代器遍历List

    迭代器依赖集合存在

  • 设计模式(17) 迭代器模式

    迭代器模式 基于IEnumerable的实现 使用场景 迭代器模式的优缺点 迭代器模式 迭代器模式用于顺序访问集合...

  • List集合

    List集合特有的方法 list集合可以用迭代器和for循环进行遍历 迭代器并发修改异常 ListIterator...

网友评论

      本文标题:集合--迭代器

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