Java8中容器在创建一个stream()流的过程中首先会创建一个相应的spliterator来作为迭代器来使用,这个迭代器支持并行迭代。
根据每个容器不同的性质,这个迭代器也对应了相应的特征量。
例如ArrayList。
public int characteristics() {
return Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED;
}
其包含三个特征量,分别ordered表示该集合产生的迭代器的迭代顺序是按照原本容器中的顺序,sized表示该迭代器的大小是有限的,而subsized表示该迭代器所分割得到的子迭代器也是有序的。
又例如TreeMap中的spliterator迭代器KeySpliterator。
public int characteristics() {
return (side == 0 ? Spliterator.SIZED : 0) |
Spliterator.DISTINCT | Spliterator.SORTED | Spliterator.ORDERED;
}
其包含的三个特征量distinct表示迭代器中数据存在唯一性,sorted表示其迭代器中的数据都经过相应的排序,而ordered则与ArrayList一致。
ArrayList中Spliaterator的实现是ArrayListSpliterator。
private final ArrayList list;
private int index; // current index, modified on advance/split
private int fence; // -1 until used; then one past last index
private int expectedModCount; // initialized when fence set
含有四个成员,list正是该迭代器所对应的数组,index则代表当前迭代器开始位置的下标,fence则代表当前结束位置的最后一个下标,而expectedModCount则存放了当该迭代器所对应的ArrayList的modCount来保证迭代器在迭代数据中原本数组中的数据并没有发生变化。
在ArrayListSpliterator中,当需要对需要迭代的数据进行分区的时候会调用trySplit()方法 ,将会根据当前的迭代器生成一个子迭代器。
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 {
expectedModCount = lst.modCount;
hi = fence = lst.size;
}
}
return hi;
}
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,
expectedModCount);
}
在尝试从一个ArrayListSpliterator中通过分割获取一个子迭代器,首先会确定当前的迭代器的最后分隔下标,如果是-1,则代表此次是第一次使用,更新当前迭代器的expectedModCount为对应容器的modCount,同时更新fence为对应容器的size。
在得到相应的fence之后,将当前迭代器内容起始位置到 起始与结束位置的中间位置赋给新的子迭代器,同时当前迭代器的起始位置更新到中间位置,也就是子迭代器的结束位置上。这样完成一次分割。
关于迭代器中数据元素的遍历操作,给出了forEachRemaining()方法,这个方法的参数是一个Consumer,通过将迭代器中的数据依次交由Consumer中的函数进行调用,达到遍历的目的。
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.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当中,顺序也是依照原本数组当中的数据顺序。最后index会直接到最后的位置,代表此次迭代的完成。最后会对数组的modCount进行验证,保证迭代过程中数据并没有发生变化。
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;
}
tryAdvance()则是对下一个元素进行函数的调用,会即使更新到下一个下标,并且在这过程中每次都会对数组的ModCount进行验证。
通过上述可以看到,ArrayListSpliiterator的三个特征值,都得到了体现。