完整代码:代码
前言
与
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 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.get(i);
action.accept(e);
return true;
}
return false;
}
//整体遍历
public void forEachRemaining(Consumer super E> 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
测试2:测试
forEachRemaining
方法,观察index
和estimateSize()
的变化
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.
forEachRemaining
中index
已经和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