集合源码解析二:迭代器

版权声明:欢迎转载,转载请标明来源 https://blog.csdn.net/weixin_41973131/article/details/88951168

一 Iterable

Iterable迭代器是一个fail-fast 与 ConcurrentModificationException的迭代器,即是当迭代器在进行遍历时若对容器进行修改可能会报ConcurrentModificationException的错误。在ArrayList解析中可以看出大量使用了expectedModCount == modCount的判断,用来判断在迭代过程中是否对容器进行了修改。

for-each 的循环内部也是使用了 Iterator 来遍历Collection,它也调用了 Iterator.next(),所以在修改元素时会检查(元素的)变化并抛出 ConcurrentModificationException。

以下是Iterable迭代器接口的源码:

// 实现了该接口的对象可以使用for-each循环遍历
public interface Iterable<T> {
    // 返回一个T类型的Iterator实例
    Iterator<T> iterator();

    // 默认方法, 相当与for-each,遍历执行每一个对象直到执行完毕或抛出异常
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    // 这个默认方法一般需要被覆写,默认实现的spliterator具有较差的分割能力,并且不会报告任何拼写错误
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

二 ListIterable

ListIterable继承于Iterable,相比于Iterable,它多了以下几个功能:

  1. 允许我们向前、向后两个方向遍历 List;
  2. 在遍历时修改 List 的元素;
  3. 遍历时获取迭代器当前游标所在位置。

迭代器没有当前所在元素一说,它只有一个**游标( cursor )**的概念,这个游标总是在元素之间。初始时它在第 0 个元素之前,调用 next() 游标后移一位。调用 previous() 游标就会回到之前位置。当向后遍历完元素,游标就会在元素 N 的后面。

以下是Iterable迭代器接口的源码:

package java.util;

public interface ListIterator<E> extends Iterator<E> {

    // 判断游标后面是否还有元素
    boolean hasNext();

    // 返回列表中的下一个元素
    E next();
    
    // 判断游标前面是否还有元素
    boolean hasPrevious();

    // 返回列表中的前一个元素并向前移动光标位置。
    E previous();

    // 返回随后调用next返回的元素的索引。(如果listiterator位于列表的末尾,则返回列表大小。)
    int nextIndex();

    // 返回随后调用previous返回的元素的索引。(如果列表迭代器位于列表的开头,则返回-1。)
    int previousIndex();

    // 从列表中删除由next或previous返回的最后一个元素(可选操作)。每次调用next或previous只能调用一次。只有在最后一次调用next或previous之后没有调用{@link #add}时,才可以执行此操作。
    void remove();

    // 将next或previous返回的最后一个元素替换为指定的元素(可选操作)。只有在上一次调用next或previous之后都没有调用remove或add时,才能执行此调用。
    void set(E e);
    
    // 在游标 前面 插入一个元素
    void add(E e);
}

猜你喜欢

转载自blog.csdn.net/weixin_41973131/article/details/88951168