Java8系列 (三) Spliterator可分迭代器
本文转载自 jdk8 Stream 解析2 - Spliterator分割迭代器。
概述
我们最为常见的流的产生方式是 collection.stream()
, 你点开Stream()
方法, 他是通过 Collection
这个上层接口两个java8 新增特性 default method
进行实现。
@Override
default Spliterator<E> spliterator() {
return Spliterators.spliterator(this, 0);
} default Stream<E> stream() {
return StreamSupport.stream(spliterator(), false);
}
这就牵扯到一个关键要点 Spliterator
:分割迭代器。
本文主要描述 Spliterator
的作用,大部分来源于你不愿意读的 JavaDoc
。
Spliterator
是 jdk8
非常重要的概念。里面的细节很值得学习玩味。
Spliterator 冗长的JavaDoc 说了什么?
基本介绍
Spliterator
是一个对源(数组,集合,io流等等)中元素进行遍历和分区的类。
可以通过 tryAdvance()
方法逐个遍历,也可以按照 forEachRemaining()
方法进行按 bulk 逐块的遍历。(内部调用的还是tryAdvance)
Spliterator
有类似 Collector
中的 characteristics
, 但都是由十六进制来表示的。
- SIZED :表示大小固定, Collection常用
- DISTINCT : 去重, Set常用
- SORTED : 有顺序的 SortedSet 会用
- 等等
原生类型的特化版本
原始类型特化的分割迭代器也被提供,和Stream类似。减少装箱和拆箱的操作
比迭代器Iterator 更加高效的遍历元素的方式
提供更加高效的方法,进行数据的迭代。Iterator
的使用需要调用两个组合方法 hasNext()
以及 next()
,同时在多线程访问的情况下还会出现竞争,你需要去同步。
而分割迭代器 Spliterator
使用函数式编程的方式,只用一个方法就可以做到这个两个函数动作。就避免了竞争 ,就是 tryAdvance()
方法。后面会介绍
Spliterator的接口方法
tryAdvance()
同时做了 hasNext()
以及 next()
的工作。
/**
* 类似于普通的 Iterator ,它会按顺序一个一个使用 Spliterator 中的元素执行action,并且如果还有其他元素要遍历就返回 true,否则返回 false。
*/
boolean tryAdvance(Consumer<? super T> action);
forEachRemaining()
是一个默认方法
,对余下的元素进行操作,直到元素全部被遍历完
一般情况下会直接调用上面的tryAdvance()
方法,但是也可以根据需要进行重写。
/**
* 对余下的元素进行操作,直到元素全部被遍历完
* 如果源是有序的,遍历也是有序的
*/
default void forEachRemaining(Consumer<? super T> action) {
do { } while (tryAdvance(action));
}
这里有一点很值得注意,方法体中的 do {} 是空的,这个是因为 tryAdvance() 方法本身就完成了两个操作 hasNext() 以及 next(),所以方法体中不需要有任何操作了。这个是 函数式编程带来的好处。以及与命令式编程的区别。
trySplit()
尝试切分源来的 Spliterator
, 返回的是(注意!!!)返回的是 分割出来的那一部分
数据,原有的数据集将不再包含这部分数据集合。两者 没有交集
。剩下的可以继续分割,也许不可以继续分割了。
举个例子,我原来有 100个元素,我通过
trySplit
切分出30
个,作为一个新的 Spliterator分割迭代器
返回,原有的,就还剩下70
个。
- 如果是原有数据集合是
ORDERD
的,分出来的也是有序的。 - 除非元素数量是无穷的,否则,最后一定会出现不能再分割的情况,这种情况下,返回的结果是
null。
Spliterator<T> trySplit();
estimateSize()
估算还剩下多少个元素需要遍历,不一定精确。
但是如果这个 Spliterator
是 SIZED
,没有被遍历或者 split, 或是 SUBSIZED
的,没有被遍历,那么他这个值一定是准确的。
long estimateSize();
还有个与之相关的默认方法,就是利用这个特性。
default long getExactSizeIfKnown() {
return (characteristics() & SIZED) == 0 ? -1L : estimateSize();
}
characteristics()
- 分割之前,返回的结果都是一致的
- 而分割之后,不保证一致
有一个默认方法用于判断 Spliterator
是否包含这个特性
default boolean hasCharacteristics(int characteristics) {
return (characteristics() & characteristics) == characteristics;
}
getComparator
如果源是SORTED
类型的,且有比较器 Comparator
的话,则返回这个 Comparator
,如果是SORTED
类型的,但是没有比较器,则返回 null
, 除此之外,都抛出异常。
接口的默认方法里,就是抛出了异常。
default Comparator<? super T> getComparator() {
throw new IllegalStateException();
}
Spliterator的8个Characteristics 特性
ORDERED
源的元素有序,tryAdvance
,forEachRemaining
和 trySplit
都会保证有序的进行元素的处理。
- 需要注意
hashSet
这类Collection
是不保证有序的 - 有
ORDERED
特性的数据,在并发计算的时候客户端也要做顺序限制的保证
DISTINCT
太简单,唯一性。 类似 Set
这样的传入集合会拥有这样的特性
SORTED
有这种特性的 Spliterator
,有一个特定的顺序。或者是所有元素都是可比较的,或者是有特定的比较器。
有
SORTED
一定会有ORDERED
SIZED
有这种属性的 Spliterator
在遍历和分割之前,estimateSize()
返回的大小是固定的,并且是准确的。
NONNULL
不为 NULL
, 大部分并发的集合,队列,Map 都可能会有这样的特性。
IMMUTABLE
不可变的。元素遍历期间不可以被 添加,替换,删除(cannot be added, replaced, or removed),否则,应该抛出异常。
CONCURRENT
支持并发操作的。
- 顶层的
Spliterator
不可以CONCURRENT
与SIZED
。 这两者是相互冲突的。 - 但是分割之后的
Spliterator
, 可能是SIZED
, 顶层不能决定底层
SUBSIZED
该 Spliterator 和所有从它拆分出来的分割迭代器都是 SIZED
以及 SUBSIZED
的。
如果分割后,没有按照要求返回SIZED
以及 SUBSIZED
属性,那么操作是不被保证的,也就是结果不可预测。
这个属性和
SIZED
的区别就是,SIZED
不保证SUBSIZED
。而SUBSIZED
会要求保证SIZED
内部特化而做的函数式接口 (OfPrimitive)
除了上面的函数,以及特性,Spliterator
迭代器中,还有几个定义在内部的接口。
OfPrimitive
重载了(overloads)了 Spliterator
的方法。用于实现特化的分割迭代器。
overloads:参数列表不同,函数名相同,与返回值类型无关,与访问修饰符无关。
注意与
override
的区别
免责声明:
本文转自网络文章,转载此文章仅为个人收藏,分享知识,如有侵权,请联系博主进行删除。
原文作者:待葡萄嗖透
原文出处:http://movingon.cn/2017/05/02/jdk8-Stream-%E8%A7%A3%E6%9E%902-Spliterator%E5%88%86%E5%89%B2%E8%BF%AD%E4%BB%A3%E5%99%A8/
Java8系列 (三) Spliterator可分迭代器的更多相关文章
- Java8系列 (七) CompletableFuture异步编程
概述 Java8之前用 Future 处理异步请求, 当你需要获取任务结果时, 通常的做法是调用 get(long timeout, TimeUnit unit) 此方法会阻塞当前的线程, 如果任务 ...
- 前端构建大法 Gulp 系列 (三):gulp的4个API 让你成为gulp专家
系列目录 前端构建大法 Gulp 系列 (一):为什么需要前端构建 前端构建大法 Gulp 系列 (二):为什么选择gulp 前端构建大法 Gulp 系列 (三):gulp的4个API 让你成为gul ...
- Web 开发人员和设计师必读文章推荐【系列三十】
<Web 前端开发精华文章推荐>2014年第9期(总第30期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...
- MyBatis学习系列三——结合Spring
目录 MyBatis学习系列一之环境搭建 MyBatis学习系列二——增删改查 MyBatis学习系列三——结合Spring MyBatis在项目中应用一般都要结合Spring,这一章主要把MyBat ...
- MySQL并发复制系列三:MySQL和MariaDB实现对比
http://blog.itpub.net/28218939/viewspace-1975856/ 并发复制(Parallel Replication) 系列三:MySQL 5.7 和MariaDB ...
- WCF编程系列(三)地址与绑定
WCF编程系列(三)地址与绑定 地址 地址指定了接收消息的位置,WCF中地址以统一资源标识符(URI)的形式指定.URI由通讯协议和位置路径两部分组成,如示例一中的: http://loc ...
- 【JAVA编码专题】 JAVA字符编码系列三:Java应用中的编码问题
这两天抽时间又总结/整理了一下各种编码的实际编码方式,和在Java应用中的使用情况,在这里记录下来以便日后参考. 为了构成一个完整的对文字编码的认识和深入把握,以便处理在Java开发过程中遇到的各种问 ...
- SQL Server 2008空间数据应用系列三:SQL Server 2008空间数据类型
原文:SQL Server 2008空间数据应用系列三:SQL Server 2008空间数据类型 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft SQL Server ...
- VSTO之旅系列(三):自定义Excel UI
原文:VSTO之旅系列(三):自定义Excel UI 本专题概要 引言 自定义任务窗体(Task Pane) 自定义选项卡,即Ribbon 自定义上下文菜单 小结 引言 在上一个专题中为大家介绍如何创 ...
随机推荐
- 2016级移动应用开发在线测试13-Location、Sensor & Network
有趣有内涵的文章第一时间送达! 喝酒I创作I分享 生活中总有些东西值得分享 @醉翁猫咪 1. 充分利用智能手机的GPS定位信息,创造了O2O的商业模式,打通了线上与线下的信息流和商流,极大地推动了移 ...
- GoCN每日新闻(2019-10-14)
GoCN每日新闻(2019-10-14) 1. 基于 Go 开源项目 MIMIO 的对象存储方案在探探的实践 https://mp.weixin.qq.com/s/YIKB_qAqqy6ydtFT_a ...
- 测试Leader应该做哪些事
一.负责测试组的工作组织和管理 1.参加软件产品开发前的需求调研和分析: 2.根据需求,概要设计和开发计划编写项目总体测试计划,详细测试计划,测试大纲和测试文档结构表(测试计划 a.已上线产品维护以及 ...
- Kerberos(一) 安装
1.服务器基本信息 操作系统:centos7 数量:2 主机名映射关系 IP hostname server 192.168.4.50 manager1 Kerberos server(kdc) 19 ...
- js DOM之基础详解
DOM(文档对象模型)是针对HTML和XML文档的一个API,描绘了一个层次化的节点树,允许开发人员添加.删除和修改页面的某一部分. HTML DOM 树形结构如下: 1.Node方面 1.1 节点类 ...
- composer.json和composer.lock有什么区别?
我们在做项目的时候,总是要安装一些依赖.composer给我们提供了很多方便.直接运行composer install. 当我们运行composer install 将会读取composer.lo ...
- android 连接蓝牙打印机 BluetoothAdapter
android 连接蓝牙打印机 BluetoothAdapter 源码下载地址:https://github.com/yylxy/BluetoothText.git public class Prin ...
- 人物-IT-李想:百科
ylbtech-人物-IT-李想:百科 李想,1981年10月出生于河北石家庄,80后企业家代表人物.曾先后创立泡泡网.汽车之家,现任车和家创始人及CEO. 1998年还在上高中的李想就开始做个人网站 ...
- odoo开发笔记 -- 模型后台方法返回前端form视图和tree视图的写法
待补充: 参考:工作单跳转到通关清单 --form(一对一) 工作单跳转到报关单列表 --tree (一对多)
- URLDoBase64
import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; ...