迭代器

Enumeration<E>

在说Iterator之前就先说一下被代替的Enumeration<E>

Public interface enumerator<E>{

Public boolean hasMoreElements();   //是否还有元素

Public E nextElement();       //返回下一个元素

}

 

Enumeration 1.0的时候就推出了在当时出现的的集合也是用Hashtable Vector也是用它来进行遍历的

jdk1.2的时候就推出了Iterator代替他

直到Jdk1.5Enumeration才加入了泛型,但是也没能拯救他

 

Iterator(迭代器)Enumeration(枚举类)区别

迭代器不仅可以读取集合中的数据还可以移除数据,Enumeration只能遍历

迭代器的名字短

迭代器支持fail-fast机制,Enumeration不支持

Enumeration本身是不支持同步的,但是在VoctorHashtable实现Enumeration,添加了同步

Iterator是支持fail-fast机制的:当多个线程对同一个集合的内容进行操作时,就可能会产生fail-fast事件。

 

迭代器Iterator(什么样的):

提供一种方法对一个容器对象中的元素进行访问,而有不暴露该对象容器的内部细节

javaItertor是一个接口,只提供了基本的规则

Public interface Iterator<E>{

Boolean hasNext();//判断是否有系一个元素

E next()//获取下一个元素

Void remove;//移除元素

default void forEachRemaining(Consumer<? super E> action) {  

    Objects.requireNonNull(action);

    while (hasNext())

        action.accept(next());

}

}

 

Java还提供了一个接口Iterable(能够...)

Public interface Iterable<T>{

Iterator<T> iterator();

    default void forEach(Consumer<? super T> action) { //foreach循环

        Objects.requireNonNull(action);

        for (T t : this) {

            action.accept(t);

        }

    }

    default Spliterator<T> spliterator() {                //jdk1.8的新迭代器

        return Spliterators.spliteratorUnknownSize(iterator(), 0);

    }

}

Iterable接口实现后会返回一个迭代器iterator;常用的集合collection类都实现了这个接口.

Spliteratorsplitable iterator可分割迭代器)接口是Java为了并行遍历数据源中的元素而设计的迭代器,这个可以类比最早Java提供的顺序遍历迭代器Iterator,但一个是顺序遍历,一个是并行遍历(等什么时候成为了dalao在研究这个都是些啥东西啊)

作用

返回一个标准的Iterable实现,实现Iterable接口了就可以通过foreach来遍历.在编译时会对foreach进行优化,转换为HashNext()next()的调

 

为什么要在弄两个接口呢,直接实现Iterator不好吗

主要是为了迭代器之间不会相互干扰.

 

Iterator接口中的核心方法next()hasNext()remove(),都是依赖当前位置。如果这些集合直接实现Iterator接口,则势必导致集合对象中包含当前迭代位置的数据(指针)。当集合在不同方法间进行传递的时候,由于当前迭代位置不可知,所以next()的结果也不可知。除非再为Iterator接口添加一个reset()方法,用来重置当前迭代位置。 而当实现Iterable则不然,每次调用都返回一个从头开始的迭代器,各个迭代器之间互不影响。

 

Iterator进行遍历的时候不能对正在遍历的容器进行改变大小的操作

看下Arraylist实现的Iterator

private class Itr implements Iterator<E> {

        int cursor;       // 表示下一个元素的索引位置

        int lastRet = -1; // 表示上一个元素的索引位置

        int expectedModCount = modCount;//预期被修改的次数

 

        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];

        }

        final void checkForComodification() {

            if (modCount != expectedModCount)

                throw new ConcurrentModificationException();

        }

 

 

        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();

            }

        }

 

    }

fail-fast机制

集合的内部有一个modCount用来记录集合被修改的次数 而迭代器自己也有一个expectedModCount记录修改次数

 

根据最上面的成员属性 可以知道modexpected刚开始是相同的 这时候如果遍历的时候直接用集合的方法修改集合那么modexpected就会不同(checkForComodification) 就会抛出concurrxxxxx的异常  

 

而如果是用迭代器自己的remove方法改动 那么两个将同时改变就不会报错

 

同时有个有趣的现象,ArrayList不用迭代器的方法删除倒数第二个元素也不是触发fail-fast机制

注意看那个hasNext方法

在删除倒数第二个元素的场景下:当倒数第二个元素时迭代完成,开始迭代最后一个元素时,此时cursor4size由于在迭代过程倒数第二个元素移除了,所以-1, 此时cursorsize相等,遍历结束,不会再进入下一个迭代,因此不会触发checkForComodification方法的fail-fast机制。

 

ListIterator

感觉Iterator不够强大,只能移除啊,好多功能没有

Java又出来一个新的接口,ListIterator接口,继承Iterator接口

双向遍历 可以在遍历期间修改集合,同时可以获取迭代器游标的在集合中的位置

遗憾的是,只有在list其子类才能使用

两个获取方式

List.listIterator()

List.listIterator(int location) 可以指定游标的位置

 

 

AbstractListlist的直接子类,就实现了ListIterator()方法,并且有两个内部迭代器实现类

 

SimpleListIteratorFullListIterator

SimpleListIterator 的主要操作最后都交给子类来实现,List 的子类 ArrayList, LinkedList, Vector 由于底层实现原理不同(数组,双向链表),具体操作类实现有所不同。

 

FullListIterator 继承了 SimpleListIterator, SimpleListIterator 实现了 Iterator 接口:

Listlterator()返回的fulllistlterator();

 

ListIterator

Public ListIterator<E> listIterator(int location){

Return new fulllistiterator(location);

}

 

SimpleListIterator的源码

private class SimpleListIterator implements Iterator<E> {

    //游标的位置,初始为 -1

    int pos = -1;

    //用来判断是否 fail-fast 的变量

    int expectedModCount;

    //记录上次迭代的位置

    int lastPosition = -1;

 

    SimpleListIterator() {

        expectedModCount = modCount;

    }

 

    //当游标没有跑到最后一个元素后面时 hasNext 返回 true

    public boolean hasNext() {

        return pos + 1 < size();

    }

 

    //获取下一个元素

    public E next() {

        if (expectedModCount == modCount) {

            try {

                //获取游标后面的元素,具体子类有具体实现

                E result = get(pos + 1);

                //更新

                lastPosition = ++pos;

                return result;

            } catch (IndexOutOfBoundsException e) {

                throw new NoSuchElementException();

            }

        }

        //当迭代时修改元素,就会报这个错

        throw new ConcurrentModificationException();

    }

 

    //删除上次迭代操作的元素

    public void remove() {

        //还没进行迭代操作就会报这个错

        if (this.lastPosition == -1) {

            throw new IllegalStateException();

        }

 

        if (expectedModCount != modCount) {

            throw new ConcurrentModificationException();

        }

 

        try {

            //调用子类实现的删除操作

            AbstractList.this.remove(lastPosition);

        } catch (IndexOutOfBoundsException e) {

            throw new ConcurrentModificationException();

        }

 

        expectedModCount = modCount;

        if (pos == lastPosition) {

            pos--;

        }

        //每次删除后都会还原为 -1,也就是说我们迭代一次后只能 remove 一次,再 remove 就会报错

        lastPosition = -1;

    }

}

//FullListIterator源码

private final class FullListIterator extends SimpleListIterator implements ListIterator<E> {

    //根据 start 指定游标位置

    FullListIterator(int start) {

        if (start >= 0 && start <= size()) {

            pos = start - 1;

        } else {

            throw new IndexOutOfBoundsException();

        }

    }

 

    //在游标前面添加元素

    public void add(E object) {

        if (expectedModCount == modCount) {

            try {

                //调用子类的添加操作,ArrayList, LinkedList,Vector 的添加操作实现有所不同

                AbstractList.this.add(pos + 1, object);

            } catch (IndexOutOfBoundsException e) {

                throw new NoSuchElementException();

            }

            //游标后移一位

            pos++;

            //!注意! 添加后 上次迭代位置又变回 -1 了,说明 add 后调用 remove, set 会有问题!

            lastPosition = -1;

            if (modCount != expectedModCount) {

                expectedModCount = modCount;

            }

        } else {

            throw new ConcurrentModificationException();

        }

    }

 

    //当游标不在初始位置(-1)时返回true

    public boolean hasPrevious() {

        return pos >= 0;

    }

 

    //游标后面的元素索引,就是游标 +1

    public int nextIndex() {

        return pos + 1;

    }

 

    //游标前面一个元素

    public E previous() {

        if (expectedModCount == modCount) {

            try {

                E result = get(pos);

                lastPosition = pos;

                pos--;

                return result;

            } catch (IndexOutOfBoundsException e) {

                throw new NoSuchElementException();

            }

        }

        throw new ConcurrentModificationException();

    }

 

    //游标前面元素的索引

    public int previousIndex() {

        return pos;

    }

 

    //更新之前迭代的元素为 object

    public void set(E object) {

        if (expectedModCount == modCount) {

            try {

                //调用子类的set

                AbstractList.this.set(lastPosition, object);

            } catch (IndexOutOfBoundsException e) {

                throw new IllegalStateException();

            }

        } else {

            throw new ConcurrentModificationException();

        }

    }

}

 

 


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