用例子解析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 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
【用例子解析Spliterator】测试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
推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- JS中的各种宽高度定义及其应用
- 由浅入深理解AOP
- 【译】20个更有效地使用谷歌搜索的技巧
- 涉毒患者(新诗)
- 参保人员因患病来不及到指定的医疗机构就医,能否报销医疗费用()
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus|MybatisPlus LambdaQueryWrapper使用int默认值的坑及解决
- MybatisPlus使用queryWrapper如何实现复杂查询
- 标签、语法规范、内联框架、超链接、CSS的编写位置、CSS语法、开发工具、块和内联、常用选择器、后代元素选择器、伪类、伪元素。