JDK8系列:Iterable、Iterator、Spliterator 迭代器

1、Iterable 接口

Iterable,即迭代器的意思。其作用是为集合类提供for-each循环遍历的支持,只要让一个类实现这个接口,该类的对象就可以成为for-each循环遍历的目标。换句话说,想让一个Java对象支持for-each遍历,只要让它的类实现Iterable接口即可

public interface Iterable<T> {

    // 在类型的元素上返回迭代器
    Iterator<T> iterator();

    // 对Iterable的每个元素执行给定的操作,直到处理完所有元素或操作引发异常。
    // 除非实现类另有指定,否则按迭代顺序(如果指定了迭代顺序)执行操作
    // 操作引发的异常将中继到调用方
    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    // 返回一个可分割迭代器
    default Spliterator<T> spliterator() {
        return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

 

2、Iterator 接口

Iterator即迭代器,是一个由集合框架提供、用于遍历一个集合的接口,并且访问集合的元素时是有序访问的。我们可以这样理解,集合的迭代器包含集合的所有元素,它们在遍历时按照一定的迭代次序进行。在迭代器中有一个光标指向最先迭代的元素,当执行next()方法时,将该元素从迭代器中删掉,然后光标往前移动指向剩下的元素中最早迭代的元素。

Iterator与枚举有些类似,不过它们有两点不同:

1)迭代器允许调用者在迭代期间从迭代器所指向的集合中删除元素

2)迭代器中的方法名称与枚举相比得到了改进(迭代器可以说是用来代替Enumeration的)

public interface Iterator<E> {

    // 判断Iterator是否有更多的元素
    boolean hasNext();

    // 返回iteration中的下一个元素
    E next();

    // 从基础集合中删除此迭代器返回的最后一个元素
    default void remove() {
        throw new UnsupportedOperationException("remove");
    }

    // 对每个剩余的元素执行给定的操作,直到所有元素都被处理或操作引发异常。
    // 如果指定了迭代顺序,则按迭代顺序执行操作。操作引发的异常将中继到调用方。
    default void forEachRemaining(Consumer<? super E> action) {
        Objects.requireNonNull(action);
        while (hasNext())
            action.accept(next());
    }
}

 

3、Spliterator 接口

JDK8 引入

Spliterator是一个可分割迭代器(splitable iterator),可以和iterator顺序遍历迭代器一起看。jdk1.8发布后,对于并行处理的能力大大增强,Spliterator就是为了并行遍历元素而设计的一个迭代器,jdk1.8中的集合框架中的数据结构都默认实现了spliterator

Iterator 和 Spliterator 相比,但一个是顺序遍历,一个是并行遍历

3.1、成员变量

public interface Spliterator<T> {

    // 表示迭代器需要按照其原始顺序迭代其中元素的
    public static final int ORDERED    = 0x00000010;

    // 迭代器中的元素是没有重复的
    public static final int DISTINCT   = 0x00000001;

    // 迭代器是按照某种方式排序的顺序迭代其中元素的
    public static final int SORTED     = 0x00000004;

    // 表示迭代器将要迭代的元素的个数是可计数的,有界的
    public static final int SIZED      = 0x00000040;

    // 迭代器迭代的元素是没有值为`null`的
    public static final int NONNULL    = 0x00000100;

    // 迭代器迭代的元素是不可改变的,也不可以增加、替换和删除
    public static final int IMMUTABLE  = 0x00000400;

    // 表示迭代器的数据源是线程安全的
    public static final int CONCURRENT = 0x00001000;

    // 表示当前迭代器所有的子迭代器(直接的或者间接的),都是`SIZED`和`SUBSIZED`的
    public static final int SUBSIZED = 0x00004000;
}

例如一个Collection实例的spliterator会报告一个SIZED的特征,一个Set实例会报告一个DISTINCT特征,等

如果一个迭代器没有报告IMMUTABLE或者CONCURRENT特征时,其绑定数据源后会检查数据源的结构化改动。后绑定的迭代器是绑定数据源发生在其第一次遍历、第一次拆分、第一次查询大小时,而不是在迭代器创建后立刻绑定数据源。和其它迭代器一样,绑定前对源的修改可以反应在迭代器遍历过程中,而绑定后的对源的修改会导致ConcurrentModificationException异常。

Spliterator的批量遍历方法(forEachRemaining())可以遍历所有元素之后优化遍历并检对源的结构化修改,而不是逐个检查元素并立即抛出失败。

Spliterator提供了estimateSize()方法用来估算迭代器中剩余元素的数量,理想情况下,它能够准确的计算迭代器中能够成功迭代的元素的数量,即使是在不准切的时候,其结果依然能够为对迭代器的下一步操作,如是直接迭代剩余元素还是继续分割迭代器提供依据。
尽管Spliterator为并发迭代提供了入口,但它依旧是线程不安全的。相反,spliterator的并发实现必须保证其在同一个时刻只有一个线程访问。调用trySplit()的线程可能会后续将迭代器交给其他线程进行迭代或者继续分割,并发的分割或者迭代同一个迭代器会导致不确定的结果。如果需要将迭代器由一个线程递交给另一个线程,需要保证递交前没有使用tryAdvance()消费任何元素。

Spliterator为原始类型中的int、long、double提供了专门的子类并默认实现了tryAdvance(java.util.function.Consumer) 和forEachRemaining(java.util.function.Consumer)。就是后面讲到的4个内部接口。

 3.2、方法

// 单个对元素执行给定的动作,如果有剩下元素未处理返回true,否则返回false
boolean tryAdvance(Consumer<? super T> action);

// 对每个剩余元素执行给定的动作,依次处理,直到所有元素已被处理或被异常终止。默认方法调用tryAdvance方法
default void forEachRemaining(Consumer<? super T> action) {
    do { } while (tryAdvance(action));
}

// 对任务分割,返回一个新的Spliterator迭代器
Spliterator<T> trySplit();

// 用于估算还剩下多少个元素需要遍历
long estimateSize();

// 当迭代器拥有SIZED特征时,返回剩余元素个数;否则返回-1
default long getExactSizeIfKnown() {
    return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
}

// 返回当前对象有哪些特征值
int characteristics();

// 是否具有当前特征值
default boolean hasCharacteristics(int characteristics) {
    return (characteristics() & characteristics) == characteristics;
}

// 如果Spliterator的list是通过Comparator排序的,则返回Comparator
// 如果Spliterator的list是自然排序的 ,则返回null
// 其他情况下抛错
default Comparator<? super T> getComparator() {
    throw new IllegalStateException();
}

3.3、内部接口

(1)OfPrimitive

public interface OfPrimitive<T, T_CONS, T_SPLITR extends Spliterator.OfPrimitive<T, T_CONS, T_SPLITR>> 
                                                                            extends Spliterator<T> {
    @Override
    T_SPLITR trySplit();


    @SuppressWarnings("overloads")
    boolean tryAdvance(T_CONS action);


    @SuppressWarnings("overloads")
    default void forEachRemaining(T_CONS action) {
        do { } while (tryAdvance(action));
    }
}

(2)OfInt 

public interface OfInt extends OfPrimitive<Integer, IntConsumer, OfInt> {

    @Override
    OfInt trySplit();

    @Override
    boolean tryAdvance(IntConsumer action);

    @Override
    default void forEachRemaining(IntConsumer action) {
        do { } while (tryAdvance(action));
    }


    @Override
    default boolean tryAdvance(Consumer<? super Integer> action) {
        if (action instanceof IntConsumer) {
            return tryAdvance((IntConsumer) action);
        }
        else {
            if (Tripwire.ENABLED)
                Tripwire.trip(getClass(),
                                "{0} calling Spliterator.OfInt.tryAdvance((IntConsumer) action::accept)");
            return tryAdvance((IntConsumer) action::accept);
        }
    }


    @Override
    default void forEachRemaining(Consumer<? super Integer> action) {
        if (action instanceof IntConsumer) {
            forEachRemaining((IntConsumer) action);
        }
        else {
            if (Tripwire.ENABLED)
                Tripwire.trip(getClass(),
                        "{0} calling Spliterator.OfInt.forEachRemaining((IntConsumer) action::accept)");
            forEachRemaining((IntConsumer) action::accept);
        }
    }
}

(3)OfLong 

public interface OfLong extends OfPrimitive<Long, LongConsumer, OfLong> {

    @Override
    OfLong trySplit();

    @Override
    boolean tryAdvance(LongConsumer action);

    @Override
    default void forEachRemaining(LongConsumer action) {
        do { } while (tryAdvance(action));
    }


    @Override
    default boolean tryAdvance(Consumer<? super Long> action) {
        if (action instanceof LongConsumer) {
            return tryAdvance((LongConsumer) action);
        }
        else {
            if (Tripwire.ENABLED)
                Tripwire.trip(getClass(),
                            "{0} calling Spliterator.OfLong.tryAdvance((LongConsumer) action::accept)");
            return tryAdvance((LongConsumer) action::accept);
        }
    }


    @Override
    default void forEachRemaining(Consumer<? super Long> action) {
        if (action instanceof LongConsumer) {
            forEachRemaining((LongConsumer) action);
        }
        else {
            if (Tripwire.ENABLED)
                Tripwire.trip(getClass(),
                            "{0} calling Spliterator.OfLong.forEachRemaining((LongConsumer) action::accept)");
            forEachRemaining((LongConsumer) action::accept);
        }
    }
}

(4)OfDouble 

public interface OfDouble extends OfPrimitive<Double, DoubleConsumer, OfDouble> {

    @Override
    OfDouble trySplit();

    @Override
    boolean tryAdvance(DoubleConsumer action);

    @Override
    default void forEachRemaining(DoubleConsumer action) {
        do { } while (tryAdvance(action));
    }


    @Override
    default boolean tryAdvance(Consumer<? super Double> action) {
        if (action instanceof DoubleConsumer) {
            return tryAdvance((DoubleConsumer) action);
        }
        else {
            if (Tripwire.ENABLED)
                Tripwire.trip(getClass(),
                            "{0} calling Spliterator.OfDouble.tryAdvance((DoubleConsumer) action::accept)");
            return tryAdvance((DoubleConsumer) action::accept);
        }
    }


    @Override
    default void forEachRemaining(Consumer<? super Double> action) {
        if (action instanceof DoubleConsumer) {
            forEachRemaining((DoubleConsumer) action);
        }
        else {
            if (Tripwire.ENABLED)
                Tripwire.trip(getClass(),
                        "{0} calling Spliterator.OfDouble.forEachRemaining((DoubleConsumer) action::accept)");
            forEachRemaining((DoubleConsumer) action::accept);
        }
    }
}

3.4、实现样例

以ArrayListSpliterator为例说明Spliterator的实现:

static final class ArrayListSpliterator<E> implements Spliterator<E> {
    //ArrayList数据源的对象引用
    private final ArrayList<E> list;
    private int index; // 起始位置所有,会被advance()和split()函数修改。
    private int fence; // 结束位置,-1表示到最后一个元素
    private int expectedModCount; // initialized when fence set

    ArrayListSpliterator(ArrayList<E> list, int origin, int fence, int expectedModCount) {
        this.list = list; // OK if null unless traversed
        this.index = origin;
        this.fence = fence;
        this.expectedModCount = expectedModCount;
    }

    private int getFence() { // initialize fence to size on first use
        int hi; // (a specialized variant appears in method forEach)
        ArrayList<E> lst;
        if ((hi = fence) < 0) {
            if ((lst = list) == null)
                hi = fence = 0;
            else {
                expectedModCount = lst.modCount;
                hi = fence = lst.size;
            }
        }
        return hi;
    }

    // 每次分割,都将原来的迭代器等分为两个,并返回索引靠前的那个
    public ArrayListSpliterator<E> trySplit() {
        int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;
        return (lo >= mid) ? null : new ArrayListSpliterator<E>(list, lo, index = mid, expectedModCount); 
    }

    // 使用action消费下一个元素
    public boolean tryAdvance(Consumer<? super E> action) {
        if (action == null)
            throw new NullPointerException();
        int hi = getFence(), i = index;
        if (i < hi) {
            index = i + 1;
            @SuppressWarnings("unchecked") 
            E e = (E)list.elementData[i];
            action.accept(e);
            if (list.modCount != expectedModCount)
                throw new ConcurrentModificationException();
            return true;
        }
        return false;
    }

    // 批量消费所有未迭代的元素
    public void forEachRemaining(Consumer<? super E> action) {
        int i, hi, mc; // hoist accesses and checks from loop
        ArrayList<E> lst; Object[] a;
        if (action == null)
            throw new NullPointerException();
        if ((lst = list) != null && (a = lst.elementData) != null) {
            if ((hi = fence) < 0) {
                mc = lst.modCount;
                hi = lst.size;
            } else
                mc = expectedModCount;
            if ((i = index) >= 0 && (index = hi) <= a.length) {
                for (; i < hi; ++i) {
                    @SuppressWarnings("unchecked") E e = (E) a[i];
                    action.accept(e);
                }
                if (lst.modCount == mc)
                    return;
            }
        }
        throw new ConcurrentModificationException();
    }

    //估算将要迭代的元素的数量
    public long estimateSize() {
        return (long) (getFence() - index);
    }

    //特征值,对于ArrayListSpliterator,其迭代顺序是按照原始顺序迭代的,而且可以预估数量。
    public int characteristics() {
        return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
    }
}

3.5、使用样例

import java.util.ArrayList;
import java.util.Spliterator;
import java.util.function.Consumer;

public class IteratorTest {
    public static void main(String[] args) {
        ArrayList<String> arrays = new ArrayList<String>();

        arrays.add("a");
        arrays.add("b");
        arrays.add("c");
        arrays.add("d");
        arrays.add("e");
        arrays.add("f");
        arrays.add("g");
        arrays.add("h");
        arrays.add("i");
        arrays.add("j");

        arrays.remove("j");

        Spliterator<String> p = arrays.spliterator();

        Spliterator<String> s1 = p.trySplit();

        Spliterator<String> s2 = p.trySplit();

        System.out.println("p.consume :");
        p.forEachRemaining(new Consumer<String>() {
            public void accept(String s) {
                System.out.println(s);
            }
        });

        System.out.println("s1.consume");
        s1.forEachRemaining(new Consumer<String>() {
            public void accept(String s) {
                System.out.println(s);
            }
        });

        System.out.println("s2.consume");
        s2.forEachRemaining(new Consumer<String>() {
            public void accept(String s) {
                System.out.println(s);
            }
        });
    }
}

结果:

这里写图片描述

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值