阅读 334

Java8不可不知的特性——Stream

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

介绍

在写算法题的时候,经常看见其他人对数组或者列表进行操作的时候没有去手动遍历一遍进行操作,而是优雅地用一行代码就能解决。如对一个列表中的所有数排序并取平方:

nums = nums.stream().sorted().map(i -> i * i).collect(Collectors.toList())
复制代码

这便是 java8 的特性——Stream,这是 java8 提供的一个抽象概念,能让我们像上面的代码一样声明式地去处理数据。

具体来说就是,它将要处理的元素(数组或列表中的元素)看成是一种,将这种流在管道中进行处理,比如排序、过滤等等,串行地执行这些操作,最终再通过 collect 将流转化为原来的数据形式或者变成其他的数据形式。

操作

具体地,我们来讨论流中有那些操作。

排序

就是对元素进行排序,如

List<Integer> nums = Arrays.asList(10, 5, 8, 2, 6, 1, 7);
System.out.println(nums.stream().sorted().collect(Collectors.toList()));
复制代码

结果为

[1, 2, 5, 6, 7, 8, 10]

过滤

根据设置的条件来过滤掉某些不要的元素,如这里只要过滤出小于等于 5 的元素:

List<Integer> nums = Arrays.asList(10, 5, 8, 2, 6, 1, 7);
System.out.println(nums.stream().filter(i -> i <= 5).collect(Collectors.toList()));
复制代码

结果为

[5, 2, 1]

限制数量

用于获取指定数量的流,如这里只要 5 个元素:

List<Integer> nums = Arrays.asList(10, 5, 8, 2, 6, 1, 7);
System.out.println(nums.stream().limit(5).collect(Collectors.toList()));
复制代码

结果为

[10, 5, 8, 2, 6]

映射

映射每个元素到对应的结果上,像函数一样,如这里取平方:

List<Integer> nums = Arrays.asList(10, 5, 8, 2, 6, 1, 7);
System.out.println(nums.stream().map(i -> i*i).collect(Collectors.toList()));
复制代码

结果为

[100, 25, 64, 4, 36, 1, 49]

并行

除了一般的串行处理,流还能并行地处理数据。只需简单地替换 stream()parallelStream() 即可。

这里的并行我思考过是在每个操作的时候处理每个数据时并行,还是针对整个管道,每个操作并行处理。后者显然串行和并行结果会有所不同。经过实验,我发现是前者,即在每个操作的时候处理每个数据时并行。所以每个操作之间的执行还是串行执行的。

List<Integer> nums = Arrays.asList(10, 5, 8, 2, 6, 1, 7);
// 先过滤再映射
System.out.println(nums.parallelStream().filter(i -> i <= 5).map(i -> i*i).collect(Collectors.toList()));
// 先映射再过滤
System.out.println(nums.parallelStream().map(i -> i*i).filter(i -> i <= 5).collect(Collectors.toList()));
复制代码

结果为

[25, 4, 1]
[4, 1]
复制代码

Collectors

这个操作就是把流转化为原来的数据形式或者变成其他的数据形式,不仅可以转化回集合,更可以将结果聚合为一个元素,例子如下:

List<Integer> nums = Arrays.asList(10, 5, 8, 2, 6, 1, 7);
// 转化为列表
System.out.println(nums.stream().filter(i -> i <= 5).map(i -> i*i).collect(Collectors.toList()));
// 聚合成一个元素
System.out.println(nums.stream().filter(i -> i <= 5).map(i -> i * i).map(String::valueOf).collect(Collectors.joining("-")));
复制代码

结果为

[25, 4, 1]
25-4-1
复制代码

除此之外,jdk 还提供许多 Collector 供开发者使用,并且还可以自定义 Collector。由于这里只是入门就不多赘述。

统计

主要用于数值型元素上,可以方便地获得一些最大最小值、平均值等统计结果。


List<Integer> nums = Arrays.asList(10, 5, 8, 2, 6, 1, 7);
IntSummaryStatistics stats = nums.stream().mapToInt((x) -> x).summaryStatistics();

System.out.println(stats);
System.out.println("最大值 : " + stats.getMax());
System.out.println("最小值 : " + stats.getMin());
System.out.println("平均数 : " + stats.getAverage());
System.out.println("所有元素之和 : " + stats.getSum());
复制代码

结果为

IntSummaryStatistics{count=7, sum=39, min=1, average=5.571429, max=10}
最大值 : 10
最小值 : 1
平均数 : 5.571428571428571
所有元素之和 : 39
复制代码

总结

这篇文章就是对 Stream 特性的一个入门探索,关于它其实还有很多内容,自定义程度非常的高,不过了解本文这些基本的操作与流式思想就基本够用在一些简单应用上了。

文章分类
后端
文章标签