用例子解析Spliterator

完整代码:代码
前言
Iterator不同的是,Spliterator可以拆分成多份去遍历,有点像二分法,每次把某个Spliterator平均分成两份,但是改的只是下标.
话不多说,先通过一个例子来说明吧
小例子
这个是我从ArrayList的源码里面拿出来的一个ArrayListSpliterator,只是去掉了modCount变量.
需要实现Spliterator接口, 接口定义大家可以自己简单去查看一下,就是要实现以下的一些方法.
static final class ArrayListSpliterator implements Spliterator {//用于存放实体变量的list private final ArrayList list; //遍历的当前位置 private int index; //结束位置(不包括) 意思是当前可用的元素是[index, fence) = [index, fence-1] private int fence; // -1 until used; then one past last index// 构造方法 ArrayListSpliterator(ArrayList list, int origin, int fence) { this.list = list; this.index = origin; this.fence = fence; }//第一次使用的时候初始化fence 返回结束位置 private int getFence() { // initialize fence to size on first use int hi; // (a specialized variant appears in method forEach) ArrayList lst; if ((hi = fence) < 0) { if ((lst = list) == null) hi = fence = 0; else { hi = fence = lst.size(); } } return hi; }/** * 根据当前的Spliterator拆分出一个新的Spliterator * 相当于二分, * Note:共享同一个list,改变的只是下标 */ public ArrayListSpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : // divide range in half unless too small new ArrayListSpliterator(list, lo, index = mid); }//单次遍历下标index只加1 public boolean tryAdvance(Consumer action) { if (action == null) throw new NullPointerException(); int hi = getFence(), i = index; if (i < hi) { index = i + 1; @SuppressWarnings("unchecked") E e = (E)list.get(i); action.accept(e); return true; } return false; }//整体遍历 public void forEachRemaining(Consumer action) { int i, hi, mc; // hoist accesses and checks from loop ArrayList lst; Object[] a; if (action == null) throw new NullPointerException(); if ((lst = list) != null && (a = lst.toArray()) != null) { if ((hi = fence) < 0) { hi = lst.size(); } if ((i = index) >= 0 && (index = hi) <= a.length) { for (; i < hi; ++i) { @SuppressWarnings("unchecked") E e = (E) a[i]; action.accept(e); } } } }//剩下还有多少元素 public long estimateSize() { return (long) (getFence() - index); }public int characteristics() { return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED; }public String toString() { return "[" + this.index + "," + getFence() + "]"; } }

测试1: 测试trySplit()方法,观察Spliterator是如何进行拆分的.
public class TestSpliterator { public static void main(String[] args) { test_trySplit(); }public static void test_trySplit() { ArrayList al = new ArrayList<>(); for (int i = 0; i <= 10; i++) al.add(i); ArrayListSpliterator als_1 = new ArrayListSpliterator(al, 0, -1); System.out.println("als_1:" + als_1); // [0,11]System.out.println("---------split-----------"); ArrayListSpliterator als_2 = als_1.trySplit(); System.out.println("als_1:" + als_1); // [5,11] System.out.println("als_2:" + als_2); // [0,5]// [0,11](als_1) ---> [0,5](als_2) + [5,11](als_1)System.out.println("---------split-----------"); ArrayListSpliterator als_3 = als_1.trySplit(); ArrayListSpliterator als_4 = als_2.trySplit(); System.out.println("als_1:" + als_1); System.out.println("als_2:" + als_2); System.out.println("als_3:" + als_3); System.out.println("als_4:" + als_4); /** * [0,5](als_2)--> [0,2](als_4)+ [2,5](als_2) * [5,11](als_1) --> [8,11](als_1) + [5,8](als_3) */System.out.println("---------test the address---------"); System.out.println("(als_1.list == als_2.list) = " + (als_1.list == als_2.list)); System.out.println("(als_2.list == als_3.list) = " + (als_2.list == als_3.list)); System.out.println("(als_3.list == als_4.list) = " + (als_3.list == als_4.list)); } }

输出1: 对照源码和测试代码结果就可以看出
1.所有Spliterator都共享一个list,因为拥有的是同一个list的地址.
2.是按下标进行二分拆分.
als_1:[0,11] ---------split----------- als_1:[5,11] als_2:[0,5] ---------split----------- als_1:[8,11] als_2:[2,5] als_3:[5,8] als_4:[0,2] ---------test the address--------- (als_1.list == als_2.list) = true (als_2.list == als_3.list) = true (als_3.list == als_4.list) = true

【用例子解析Spliterator】测试2:测试forEachRemaining方法,观察indexestimateSize()的变化
public class TestSpliterator { public static void main(String[] args) { test_forEachRemaining(); System.out.println("---------------------"); test_tryAdvance(); }public static void test_tryAdvance() { ArrayList al = new ArrayList<>(); for (int i = 0; i <= 10; i++) al.add(i); ArrayListSpliterator als_1 = new ArrayListSpliterator(al, 0, -1); als_1.tryAdvance(new Consumer(){ @Override public void accept(Integer t) { System.out.print(t + " "); } }); System.out.println("\nals_1:" + als_1); System.out.println("left size:" + als_1.estimateSize()); }public static void test_forEachRemaining() { ArrayList al = new ArrayList<>(); for (int i = 0; i <= 10; i++) al.add(i); ArrayListSpliterator als_1 = new ArrayListSpliterator(al, 0, -1); als_1.forEachRemaining(new Consumer(){ @Override public void accept(Integer t) { System.out.print(t + " "); } }); System.out.println("\nals_1:" + als_1); System.out.println("left size:" + als_1.estimateSize()); } }

输出2:
1.forEachRemainingindex已经和getFence()相等了,并且剩下的size已经没有了,表示已经消费完了.
2.tryAdvance中只是消费了一个,所以index只是增加了1,并且剩下的size只是减少了1.
0 1 2 3 4 5 6 7 8 9 10 als_1:[11,11] left size:0 --------------------- 0 als_1:[1,11] left size:10

int characteristics()方法
a representation of characteristics这个是定义了该Spliterator的属性. 建议大家自己去看一下英文的注释解释得比较清楚.
public static final int CONCURRENT = 0x00001000; //表示线程安全的 public static final int DISTINCT= 0x00000001; // 元素是独一无二的 public static final int IMMUTABLE= 0x00000400; //元素不可变在遍历过程中不能删除修改增加 public static final int NONNULL= 0x00000100; //元素不能为null public static final int ORDERED= 0x00000010; //迭代器按照原始的顺序迭代 public static final int SIZED= 0x00000040; //元素可以计数 public static final int SORTED= 0x00000004; //元素是有序的 public static final int SUBSIZED = 0x00004000;

参考
1.java1.8 java.util.ArrayList

    推荐阅读