- Java8核心新特性
- Stream流
- Optional
- Lambda匿名函数
- 默认方法
本篇重点介绍Stream
Stream流
从支持数据处理操作的源,生成的元素序列
- 元素序列:流提供接口,可以访问特定元素类型的一组有序值,流的目的在于表达计算
- 源:流会使用一个提供数据的源,如集合、数组或输入/输出资源
- 数据处理操作:提供类似于数据库的操作,以及函数式编程语言中的常用操作(filter、map、reduce、find、match、sort等),串行或并行均支持
- 并行:很多流操作本身会返回一个流,这样多个操作就可以链接起来,形成一个流水线(可以进行延迟和短路等优化)
- 内部迭代:流的迭代操作是在后台进行的
1 | /** |
优点
- 声明性
- 简洁易读
- 想要完成什么,而不是说明如何实现一个操作(利用循环和if条件等控制流语句)
- 可复合:灵活
- 可并行:性能更好
缺点
debug
时需要将将语句切换为多行(例如以.
换行)才可以打断点只能遍历一次
s.forEach
第二次调用会报java.lang.IllegalStateException: stream has already been operated upon or closed
异常
与集合对比
- 存储
- 集合:内存中的数据结构,包含所有值
- 流:概念上固定的(不能添加或删除)
- 计算时机
- 集合:元素需先计算出来才能成为集合的一部分
- 流:按需计算,只有在有需要时才会计算值
- 创建
- 集合:急切创建,先装满再处理
- 流:延迟创建,需要时再计算值
- 迭代
- 集合:外部迭代(
for-each
) - 流:内部迭代(透明并行、优化处理顺序)
- 集合:外部迭代(
操作
- 中间操作
- 可以连接起来的流操作
filter
、map
、limit
- 可以连接起来的流操作
- 终端操作
- 结果为不是流的值
使用
筛选和切片
筛选(distinct)
1 | //2、4 |
截短流limit
1 | //2 |
跳过skip
1 | //4 |
映射
map
创建一个新版本
1 | List<String> dishNames = menu.stream() |
flatmap
将结果合并为一个流
1 | List<String> uniqueCharacters = |
查找和匹配
- 短路
- allMatch:流中的元素是否都能匹配
- anyMatch:流中的元素是否有一个元素能匹配
- noneMatch:确保流中没有任何元素匹配
- findFirst:返回第一个匹配的值(并行流上限制多)
- findAny:返回任意匹配的值(并行流上限制少)
规约
元素求和
1 | // reduce(初始值,BinaryOperator<T>来将两个元素结合起来产生一个新值) |
最大值
1 | numbers.stream().reduce(0, Integer::max); |
最小值
1 | numbers.stream().reduce(0, Integer::min); |
流类型
数值流、多种来源流(文件、数组)、无限流
数值流
避免暗含的装箱成本
IntStream
:mapToInt
、OptionalInt
DoubleStream
:mapToDouble
、OptionalDouble
LongStream
:mapToLong
、OptionalLong
数值流转换为一般流可用
boxed()
方法
1 | Stream<Integer> stream = intStream.boxed(); |
数值范围
- 可用于
IntStream
和LongStream
range
:不包含结束值rangeClosed
:包含结束值
多种来源流(文件、数组)
1 | // 创建流 |
无限流
Stream.iterate
- 需要依次生成一系列值
- 斐波那契数列
- 对象无可变状态
- 需要依次生成一系列值
应该使用limit(n)来对流加以限制,防止一直计算
1 | Stream.iterate(0, n -> n + 2) |
Stream.generate
- 按需生成
- 对象有可变的状态
1 | Stream.generate(Math::random) |
收集数据
区分
- Collection
- Java集合的祖先接口
- Collections
java.util
包下的工具类- 内置各种处理集合的静态方法
- Collector
- 接口
- 创建常见常见收集器实例
Collectors.counting()
:计数Collectors.maxBy()
:求最大Collectors.minBy()
:求最小Collectors.summingInt()
:汇总Collectors.averaginInt()
:求平均值Collectors.joining()
:拼接字符串Collectors.reducing(startValue, lambda, BinaryOperator)
:规约Collectors.groupingBy(lambda)
:分组Collectors.partitioningBy(lambda)
:分区
- 功能
- 将流元素规约和汇总为一个值
- 元素分组
- 元素分区
Collectors.toList()
- collect
java.util.stream.Stream#collec
- 负责收集流
- 适合表达可变容器上的规约
- Collections
- 集合类的工具类
- 排序
- 搜索
- 集合类的工具类
- Optional
- isPresent():包含值的时候返回true,否则返回false
- get():在值存在时返回,否则抛出一个
NoSuchElement
异常 - orElse(T other):会在值存在时返回,否则返回一个默认值
- 处理流的方式分为惰性求值和及早求值,对流的处理通常包括一系列的惰性求值和一个及早求值,流遇到及早求值时,才会真正的遍历和执行
- 函数式编程时,函数应该是没有副作用的,对象不应该被修改,如果需要修改对象,则采用map方法