集合源码学习(二):Spliterator
来源:互联网 发布:a5源码被骗 编辑:程序博客网 时间:2024/05/17 08:48
何为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;}
相关特征值具体意思:
衍生的接口
另外,在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,里面包含什么特征就写什么特征。
阅读全文
0 0
- 集合源码学习(二):Spliterator
- JDK8源码之Spliterator并行遍历迭代器
- Java集合源码学习(二)ArrayList分析
- 集合学习(二)
- 集合学习总结二
- 虫虫的java之旅(集合篇)1---Collection的后续spliterator,stream,parallelStream
- 集合学习--ArrayList 源码初探
- 集合学习--LinkedList 源码初探
- 集合学习--HashMap 源码初探
- 集合学习--HashTable 源码初探
- 集合源码学习(一):Collection
- 集合源码学习(三):ArrayList
- 集合源码学习(四):Vector
- 集合源码学习(五):LinkedList
- 集合源码学习(六):TreeMap
- 集合源码学习(十一):LinkedHashMap
- 集合学习--TreeMap 源码初探
- lua_gc 源码学习二
- ImageLoader
- 【Java基础09_3】接口
- MySQL 5.7.17 安装报错CMake Error at cmake/boost.cmake:81 (MESSAGE)
- AppCompatActivity
- 2017033000C++函数参数和返回值三种传递方式:值传递、指针传递和引用传递(着重理解)
- 集合源码学习(二):Spliterator
- (M)Dynamic Programming:304. Range Sum Query 2D
- Word Construction hiho一下第170周
- STL(下篇)
- ucosII(一)
- MongoDB&C++开发 (六)使用bsoncxx::builder::stream和$push在数组中插入元素
- 淘宝详情页广告法检测工具 淘宝违规词检测、查询 淘宝详情页违规词检测、查询
- 如何利用js制作选项卡
- namenode 异常关闭问题查询