1、什么是流?
Java Se中对于流的操作有输入输出IO流,而Java8中引入的Stream 属于Java API中的一个新成员,它允许你以声明性方式处理数据集合,Stream 使用一种类似 SQL 语句从数据库查询数据的直观方式来提供一种对 Java 集合运算和表达的高阶抽象。 注意这里的流操作可以看做是对集合数据的处理。
简单来说,流是一种数据渠道,用于操作数据源(集合、数组)所生产的元素序列。
- 元素序列 :就像集合一样,流也提供了一个接口,可以访问特定元素类型的一组有序值。
- 源:流会使用一个提供数据的源,如集合、数组或输入/输出资源。 请注意,从有序集 合生成流时会保留原有的顺序。由列表生成的流,其元素顺序与列表一致
- 数据处理操作:流的数据处理功能支持类似于数据库的操作,以及函数式编程语言中 的常用操作,如filter、 map、 reduce、 find、 match、 sort等。流操作可以顺序执 行,也可并行执行。
- 流水线:很多流操作本身会返回一个流,这样多个操作就可以链接起来,形成一个大 的流水线。
- 内部迭代:与使用迭代器显式迭代的集合不同,流的迭代操作是在背后进行的。
2、流操作
整个流操作就是一条流水线,将元素放在流水线上一个个地进行处理。需要注意的是:很多流操作本身就会返回一个流,所以多个操作可以直接连接起来, 如下图这样,操作可以进行链式调用,并且并行流还可以实现数据流并行处理操作。
3、流与集合
3.1、计算的时机
Stream 和集合的其中一个差异在于什么时候进行计算,集合,它会包含当前数据结构中所有的值,你可以随时增删,但是集合里面的元素毫无疑问地都是已经计算好了的。 流则是按需计算,按照使用者的需要计算数据,你可以想象我们通过搜索引擎进行搜索,搜索出来的条目并不是全部呈现出来的,而且先显示最符合的前 10 条或者前 20 条,只有在点击 “下一页” 的时候,才会再输出新的 10 条。
5.3.2、外部迭代与内部迭代
把集合比作一个工厂的仓库,一开始工厂比较落后,要对货物作什么修改,只能工人亲自走进仓库对货物进行处理,有时候还要将处理后的货物放到一个新的仓库里面。在这个时期,我们需要亲自去做迭代,一个个地找到需要的货物,并进行处理,这叫做外部迭代。
后来工厂发展了起来,配备了流水线作业,只要根据需求设计出相应的流水线,然后工人只要把货物放到流水线上,就可以等着接收成果了,而且流水线还可以根据要求直接把货物输送到相应的仓库。这就叫做内部迭代,流水线已经帮你把迭代给完成了,你只需要说要干什么就可以了(即设计出合理的流水线)。
Java 8 引入 Stream 很大程度是因为,流的内部迭代可以自动选择一种合适你硬件的数据表示和并行实现。
4、创建流
在 Java 8 中, 集合接口有两个方法来生成流:
- stream() − 为集合创建串行流。
- parallelStream() − 为集合创建并行流。
示例代码如下:
上述操作得到的流是通过原始数据转换过来的流,除了这种流创建的基本操作外,对于流的创建还有以下几种方式。
4.1、值创建流
4.2、数组创建流
根据参数的数组类型创建对应的流。
- Arrays.stream(T[ ])
- Arrays.stream(int[ ])
- Arrays.stream(double[ ])
- Arrays.stream(long[ ])
4.3、文件生成流
4.4、函数生成流
两个方法:
- iterate : 依次对每个新生成的值应用函数
- generate :接受一个函数,生成一个新的值
5、流的中间操作
常见的流的中间操作,归为以下三大类:筛选和切片流操作、元素映射操作、元素排序操作:
5.1、筛选和切片
例如以订单数据为例,在做报表展示时,会根据订单状态、用户信息、支付结果等状态来分别展示(即过滤和统计展示)
定义订单Order类
测试
5.2、映射
5.3、排序
6、流的终止操作
终止操作会从流的流水线生成结果。其结果是任何不是流的值,比如常见的List、 Integer,甚 至void等结果。
对于流的终止操作,分为以下三类:
6.1、查找与匹配
6.2、归约
6.3、Collector收集数据
6.3.1、收集
将流转换为其他形式,coollect 方法作为终端操作, 接收一个Collector接口的实现,用于给Stream中元素做汇总的方法。最常用的方法,把流中所有元素收集到一个 List, Set 或 Collection 中
- toList
- toSet
- toCollection
- toMap
6.3.2、汇总
- countintg():用于计算总和
- count():用于计算总和(推荐使用,写法更简洁)
- summingInt() ,summingLong(),summingDouble():用于计算总和
- averagingInt(),averagingLong(),averagingDouble()用于平均
- summarizingInt,summarizingLong,summarizingDouble 同样可以实现计算总和,平均等操作,比如summarizingInt 结果会返回IntSummaryStatistics 类型 ,然后通过get方法获取对应汇总值即可
6.3.3、最值
6.3.4、分组
groupingBy 用于将数据分组,最终返回一个 Map 类型
groupingBy 可以接受一个第二参数实现多级分组
6.3.5、partitioningBy 分区