Stream流(二)
Stream操作api
Stream
流常用的操作api
如下:
方法 | 返回值 | 说明 |
---|---|---|
filter | Stream | 过滤数据 |
map | Stream | 返回新的数据类型 |
flatMap | Stream | 返回新的数据类型,并作扁平化处理 |
distinct | Stream | 去重 |
sorted | Stream | 排序 |
limit | Stream | 获取前几条数据 |
skip | Stream | 跳过前几条数据 |
forEach | void | 遍历元素 |
reduce | Optional | 数据汇总 |
collect | R | 收集数据 |
count | long | 数据个数统计 |
anyMatch | boolean | 数据任意一个匹配 |
allMatch | boolean | 数据全匹配 |
noneMatch | boolean | 数据全不匹配 |
findFirst | Optional | 获取第一个数据 |
findAny | Optional | 获取任意一个数据 |
1、forEach
forEach
方法接受一个Consumer
接口函数,会将每一个流元素交给函数进行处理。
1 | // 例子:forEach输出元素 |
2、filter
filter
方法用来筛选出我们想要的数据,方法参数是一个Predicate
接口,因为Predicate
是一个函数式接口,我们可以使用Lambda
表达式来写。
1 | // 例子1:过滤出大于3的数 |
3、map
map
方法用于将一种数据类型转换另一种数据类型,方法参数是Function
函数接口参数,该函数接口可以把数据类型T(函数接口输入)换成数据类型R(函数接口输出)
1 | // 例子:map将整数转换成集合 |
4、flatMap
flatMap
方法也可以将一种数据类型转换另一种数据类型,方法参数也是Function
函数接口参数,该函数接口传参和map
方法一样是数据类型T,但是输出是数据类型R对应的Stream
流对象,因此上述的map
的例子改写成flatMap
的方式是:
1 | // 例子:flatMap将整数转化成集合 |
flatMap
和map
转换的区别点在于:
map
必须是一对一的,即每个元素都只能转换为 1 个新的元素
flatMap
可以是一对多的,即每个元素都可以转换为1个或者多个新的元素
实际上flatMap
操作将每个元素处理返回一个新的 Stream
,然后将多个 Stream
展开合并为了一个完整的新的 Stream
正如上述所说,map
是将元素一对一的转换,flatMap
可以将元素一对多的转换,因此当遇到需要一转多的情况时,flatMap
更适用
1 |
|
上述例子中,
role.getUserIdList().stream();
不要写成Stream.of(role.getUserIdList());
,因为如果是后者的话,flatMap
操作元素生成的Stream
流的元素是个集合,最后合并的Stream
的元素也是集合如果是前者的话,其
Stream
流元素就是Integer
5、distinct
distinct
方法用于对流中的元素进行去重,主要是根据元素对应类的equals
方法来判断是不是同一元素
1 | Stream.of(1, 1, 2, 3, 4, 3, 5) |
6、sorted
sorted
用于给元素进行排序,传入参数是一个比较器
1 |
|
sorted
也可以不传参数,此时会有个默认的比较器Comparators.NaturalOrderComparator.INSTANCE
,但这时候需要排序的类实现Comparable
类并实现compareTo
方法,不然会报错。我们常用的
String
类和Integer
实际上都实现了Comparable
类
7、reduce
reduce
方法用于数据的聚合、汇总
reduce
方法的参数可以归纳为如下:
- identity:数据聚合的初始值,会一起参与数据聚合
- accumulator:累加器(数据的聚合方法),定义一个带两个参数的函数,第一个参数是上个归并函数的返回值,第二个是Strem 中下一个元素。
- combiner:调用一个函数来组合聚合结果,当并行流或者累加器的函数和累加器的实现类型不匹配时才会调用此函数。
7.1 单个参数
传入单个参数时,参数是数据的聚合方法(accumulator)
1 | // 获取数组的和 |
我们可以看到,
reduce
单个参数时,需要的BinaryOperator<T>
对象是个函数接口,其继承了BiFunction<T,T,T>
接口,因此,BinaryOperator<T>
对象的实现仅需要实现BiFunction<T,T,T>
接口的R apply(T t, U u)
的方法即可。该方法需要传两个参数,返回一个值,因此上述例子可以写成
1
2
3 Optional<Integer> reduce = Stream.of(1, 2, 3, 4, 4, 5, 6, 2, 3, 5)
.reduce((a, b) -> a + b);
System.out.println(reduce);当计算数组内所有数字的乘积是就可以写成
1
2
3
4 Optional<Integer> reduce = Stream.of(1, 2, 3, 4, 4, 5, 6, 2, 3, 5)
.reduce((a, b) -> a * b);
System.out.println(reduce);
// 结果 Optional[86400]
7.2 两个参数
传入两个参数时,第一个参数是数据聚合的初始值(identity),第二个参数是数据的聚合方法(accumulator)
1 | // 获取数组的和 |
7.3 三个参数
传入三个参数时,第三个参数的组合器只有在并行流或者累加器的函数和累加器的实现类型不匹配时才会调用。因此这个方法不常用。
1 | // 获取数组的和 |
当对一个流进行并行操作时,在运行时会把流分割多个子流来并行操作。因此需要一个函数来组合各个子流返回的结果。
上述例子中,因为是并行流,10个元素分成了10个流,而每个子流的初始值都是100,因此实际上是10个100与数组的和
8、collect
collect
方法用于收集流元素,并将其转换成需要的格式,其传参有两种,不过主要是使用传Collector
的方式
1 | // 收集成List |
collect
的传参:
1
2
3
4
5
6 // 传参方式一
<R> R collect(Supplier<R> supplier,
BiConsumer<R, ? super T> accumulator,
BiConsumer<R, R> combiner);
// 传参方式二
<R, A> R collect(Collector<? super T, A, R> collector);因为
Collector
中同样提供了Supplier<R> supplier
,BiConsumer<R, ? super T> accumulator
,BiConsumer<R, R> combiner
这三个参数,所以基本都使用的方式二
更多方法的使用可以看看对应的文档或源码