StreamAPI
Stream API
Optional 类(
Stream API中的大部分返回的都是Stream类型,但是也有个别api返回的是Optional类型,如findany(),findone()等
Optional基础知识
操作符
什么是操作符呢?
操作符就是对数据进行的一种处理工作,一道加工程序;就好像工厂的工人对流水线上的产品进行一道加工程序一样。
操作符分类
-
中间操作符(可以链式调用)
- 对于数据流来说,中间操作符在执行制定处理程序后,数据流依然可以传递给下一级的操作符
-
终止操作符
- 终止操作符就是用来对数据进行收集或者消费的,数据到了终止操作这里就不会向下流动了,终止操作符只能使用一次。
中间操作符
map(mapToInt,mapToLong,mapToDouble)
转换操作符,把比如 A->B,这里默认提供了转 int,long,double 的操作符。flatmap(flatmapToInt,flatmapToLong,flatmapToDouble)
拍平操作比如把int a[][]={{1,2,3},{4,5,6}};
拍平 变成1,2,3,4,5,6
也就是从原来的一个数据变成了 6 个数据,适用于二维数组,这里默认提供了拍平成 int,long,double 的操作符。limit
限流操作,比如数据流中有 10 个 我只要出前 3 个就可以使用。distint
去重操作,对重复元素去重,底层使用了 equals 方法。filter
过滤操作,把不想要的数据过滤。peek
挑出操作,如果想对数据进行某些操作,如:读取、编辑修改等。skip
跳过操作,跳过某些元素。sorted(unordered)
排序操作,对元素排序,前提是实现 Comparable 接口,当然也可以自定义比较器。
终止操作符
- collect 收集操作,将所有数据收集起来,这个操作非常重要,官方的提供的 Collectors 提供了非常多收集器,可以说 Stream 的核心在于 Collectors。
- count 统计操作,统计最终的数据个数。
- findFirst、findAny 查找操作,查找第一个、查找任何一个 返回的类型为 Optional。
- noneMatch、allMatch、anyMatch 匹配操作,数据流中是否存在符合条件的元素 返回值为 bool 值。
- min、max 最值操作,需要自定义比较器,返回数据流中最大最小的值。
- reduce 规约操作,将整个数据流的值规约为一个值,count、min、max 底层就是使用 reduce。
- forEach、forEachOrdered 遍历操作,这里就是对最终的数据进行消费了。
- toArray 数组操作,将数据流的元素转换成数组。
//todo:
- 这里只介绍了 Stream,并没有涉及到 IntStream、LongStream、DoubleStream,这三个流实现了一些特有的操作符,我将在后续文章中介绍到
Stream 的一系列操作必须要使用终止操作,否者整个数据流是不会流动起来的,即处理操作不会执行。
创建 Stream 对象的两种方式
代码演练
map
-
功能
- map() 方法可以将一个流转换成另外一种对象的流,其中的 T 是原始流中元素的类型,而 R 则是转换之后的流中元素的类型。
- map 生成的是个 1:1 映射,每个输入元素,都按照规则转换成为另外一个元素
-
-
-
mapToInt
- 功能
- mapToInt 将数据流中得元素转成 Int,这限定了转换的类型 Int,最终产生的流为 IntStream,及结果只能转化成 int。
mapToLong、mapToDouble 与 mapToInt 类似
flatmap
-
官方理解
-
<R> Stream<R> flatMap(Function<? super T,? extends Stream<? extends R>> mapper)
。它可以将每个元素(这些元素应该是 列表 )映射为一个流,并将所有流连接成一个流。这主要用于解决嵌套集合的情况。
-
-
功能
-
作用就是将元素拍平拍扁 ,将拍扁的元素重新组成 Stream,并将这些 Stream 串行合并成一条 Stream
-
flatMap() 操作能把原始流中的元素进行一对多的转换,并且将新生成的元素全都合并到它返回的流里面。
-
这里跟 map 还不太一样
- map 是把一个个 T 类型直接转成一个个 R 类型
- flatMap 是把一个个 T 类型转成一个个 Stream
类型,然后再把这些 Stream 串行合并成一条 Stream
-
-
-
-
-
如果你有一个三层嵌套的列表,比如
List<List<List<Integer>>>
,你需要使用两次flatMap
操作才能将其转化为一个List<Integer>
。这是因为每次
flatMap
操作只能将一层的嵌套结构扁平化。第一次flatMap
将List<List<List<Integer>>>
转化为List<List<Integer>>
,第二次flatMap
将List<List<Integer>>
转化为List<Integer>
。下面是一个示例:
List<List<List<Integer>>> listOfListsOfLists = Arrays.asList(Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6)),Arrays.asList(Arrays.asList(7, 8, 9), Arrays.asList(10, 11, 12)) );
List<Integer> flattenedList = listOfListsOfLists.stream()
.flatMap(List::stream)
.flatMap(List::stream)
.collect(Collectors.toList());// flattenedList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
在这个例子中,我们先对最外层的列表进行了
flatMap(List::stream)
操作,将其转化为了一个List<List<Integer>>
,然后再次对结果进行了flatMap(List::stream)
操作,将其转化为了一个List<Integer>
。
flatmapToInt、flatmapToLong、flatmapToDouble 跟 flatMap 都类似的,只是类型被限定了,这里就不在举例子了。
limit
-
功能
- limit 限制元素的个数,只需传入 long 类型 表示限制元素的最大个数
-
源码:没有使用 lambda 表达式,没有函数式接口,只需要传入一个 long 值,具体的实习交给了 Stream 的子类去实现了 limit()方法
-
-
distinct
-
功能
- distinct 将根据 equals() 方法进行判断,如果要对自己自定义的 bean 去重,则需要重写 equals 方法,但是这不是唯一的方法,后面文章我将带大家实现自定义(bean 的某个字段去重)去重。
-
-
-
filter
-
功能
- filter 对某些元素进行过滤,不符合筛选条件的将无法进入流的下游
-
源码
-
代码
-
结果
peek
-
功能
- 将流中的所有元素进行某种操作,类似 forEach(),但是 forEach()是终止操作符,而 peek()是中间操作符
-
源码
-
代码
-
结果
skip
-
功能
- skip(long n):跳过前 n 个元素
-
源码
-
代码
-
结果
sorted
-
功能
- sorted 排序 底层依赖 Comparable 实现,也可以提供自定义比较器
-
源码
-
-
-
-
collect
-
功能
- collect 收集,使用系统提供的收集器可以将最终的数据流收集到 List,Set,Map 等容器中。
-
源码
-
代码
-
结果
count
-
功能
- count 统计数据流中的元素个数,返回的是 long 类型
-
源码
-
代码
-
结果
findFirst
-
功能
- 获取流中的第一个元素
-
源码
-
代码
-
结果
findany
-
功能
- 获取流中任意一个元素
-
源码
-
代码
-
结果
noneMatch
-
功能
- 数据流中所有元素没有一个与条件匹配的
-
源码
-
代码 1
-
结果 1
-
代码 2
-
结果 2
allMatch 和 anyMatch 一个是全匹配,一个是任意匹配 和 noneMatch 类似,这里就不在举例了。
noneMatch
- 功能
- 源码
- 代码
- 结果
noneMatch
- 功能
- 源码
- 代码
- 结果
noneMatch
- 功能
- 源码
- 代码
- 结果