何为Spliterator?
Java8新增加了Spliterator类,和以前的Iterator迭代器相比,Spliterator又被称为分割迭代器,即可以支持不同位置访问方式迭代,即并行的方式进行迭代。
先看注解后的代码:
public interface Spliterator<T> {
/**
* 执行一个元素的操作,也就是action里面的操作,如果有元素则返回true
* 没有元素返回false。
*/
boolean tryAdvance(Consumer<? super T> action);
/**
* 以此执行所有元素的action里面动作
*/
default void forEachRemaining(Consumer<? super T> action) {
do { } while (tryAdvance(action));
}
/**
* 如果这个(集合)能够被分割,返回一个分割迭代器
* @return
*/
Spliterator<T> trySplit();
/**
* 返回元素的估计数量,可以用forEachRemaining来获得,
* 如果由于元素太多或者并不知道数量
* 返回Long里面的MAX_VALUE
*/
long estimateSize();
/**
* 如果知道就返回准确数字,否则返回-1.
*/
default long getExactSizeIfKnown() {
return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
}
/**
* 返回对象具有哪些特征值:
* 例如有以下可选:
* 表明元素有哪些特征
* #ORDERED
* #DISTINCT
* #SORTED
* #SIZED
* #NONNULL
* #IMMUTABLE
* #CONCURRENT
* #SUBSIZED
*/
int characteristics();
/**
* 如果分割迭代器包括所给的所有特征,则返回true
* 具体实现的方法
*/
default boolean hasCharacteristics(int characteristics) {
return (characteristics() & characteristics) == characteristics;
}
/**
* 如果这个分割迭代器的元素是通过Comparator排好序的SORTED元素,就返回Comparator,
* 如果元素不是SORTED的,则抛出错误。
*/
default Comparator<? super T> getComparator() {
throw new IllegalStateException();
}
//众多特征值
public static final int ORDERED = 0x00000010;
public static final int DISTINCT = 0x00000001;
public static final int SORTED = 0x00000004;
public static final int SIZED = 0x00000040;
public static final int NONNULL = 0x00000100;
public static final int IMMUTABLE = 0x00000400;
public static final int CONCURRENT = 0x00001000;
public static final int SUBSIZED = 0x00004000;
}
相关特征值具体意思:
类型 | 描述 |
---|---|
CONCURRENT | 特征值表示可以通过多个线程安全同时修改元素源(允许添加,替换和/或删除),而无需外部同步。 |
DISTINCT | 特征值表示,对于每对遇到的元素x, y,!x.equals(y) |
IMMUTABLE | 特征值表示元素源不能在结构上进行修改; 也就是说,不能添加,替换或删除元素,因此在遍历过程中不会发生这种更改。 |
NONNULL | 特征值表示源保证遇到的元素不会null。 |
ORDERED | 特征值表示为元素定义遇到顺序。 |
SIZED | 特征值表示从estimateSize()遍历或分割之前返回的值 表示有限大小,在没有结构源修改的情况下,表示完全遍历将遇到的元素数量的精确计数。 |
SORTED | 特征值表示遇到的顺序遵循定义的排序顺序。 |
SUBSIZED | 特征值表示由所产生的所有Spliterator trySplit()都将SIZED和SUBSIZED。 |
衍生的接口
另外,在Spliterator源码里面还有一些衍生的接口:OfInt, OfDouble, OfLong以及OfPrimitive
,从代码里面可以看出来,结构大部分和Spliterator相同,这里介绍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));
}
}
由上代码可知,OfPrimitive
只是在原接口基础上,又增加了两个泛型,用于限定tryAdvance
和forEachRemaining
的参数。相当于规范化了一遍。
ArrayList里面用到的Spliterator
先看我注释过的源码:
static final class ArrayListSpliterator<E> implements Spliterator<E> {
private final ArrayList<E> list; //传入的ArrayList
private int index; // 当前位置
private int fence; // 末尾位置
private int expectedModCount; // modcount,即同时修改的线程数。
/** 在给定的集合范围内创建一个Spliterator */
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;
}
/**
* 获取末尾位置
* @return
*/
private int getFence() {
int hi;
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); //返回分割前半段一个Spliterator
}
/**
* 执行一个action,并使index+1
* @param action
* @return
*/
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;
}
/**
* 遍历本Spliterator下面所有元素,并执行action。
* 注意是本Spliterator
* 多余一个线程会报错
*/
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();
}
/**
* 在ArrayList中,估计大小是确定的,但这仅仅是本Spliterator里面的
* @return
*/
public long estimateSize() {
return (long) (getFence() - index);
}
/**
* 说明在ArrayList中,它的Spliterator具有哪些特征。
* 顺序性,
* 可确定范围
* 分割下去的子Spliterator也是可却定范围的。
* @return
*/
public int characteristics() {
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
}
当然如果自己想写过一个类,也可以模仿ArrayListSpliterator写一个Spliterator实现类,定义自己的特征
接下来看ArrayList结合ArrayListIterator的简单应用:
public static void main(String[] args) {
List<Character> arrs = new ArrayList<Character>();
for (int i = 97; i < 122; i++) {
arrs.add((char) i);
}
// 此时结果:spliterator1:index=0,fence=-1
//由源码可知,-1也就是代表集合长度,即25
Spliterator<Character> spliterator1 = arrs.spliterator();
// 此时结果:spliterator2:index=0,fence=12
// spliterator1:index=12,fence=25,
Spliterator<Character> spliterator2 = spliterator1.trySplit();
// 此时结果:spliterator3:index=12,fence=18
// 而 spliterator1:index=18,fence=25
Spliterator<Character> spliterator3 = spliterator1.trySplit();
// 此时结果:spliterator4:index=18,fence=21,
// spliterator1:index=21,fence=25,
Spliterator<Character> spliterator4 = spliterator1.trySplit();
}
至此,Spliterator,正如命名一样,就是一个可分割的迭代器,以前传统的Iterator能够迭代整个集合,但是不能迭代一部分,而Spliterator则可以迭代集合的一部分,同时,自己实现时,可以让其支持并行而不加锁的迭代一个集合。而Spliterator的特征值,仅仅是表示特征而已,程序员自己实现的Spliterator,里面包含什么特征就写什么特征。