本篇博客是在看代码的时候看到使用Java8使用
Stream
去重的妙用,从而对Java如何使用Stream实现几行代码
完成一个可支持并行化的流式计算程序
引言 #
什么是
Stream
简单来说Stream
就是Java8引入的一种流式API,让只需要定义一些处理函数就能优雅的对集合的一些操作
举个栗子,之前我们想遍历打印所有的参数我们得写下面代码
for (int i : new int[]{1, 2, 3, 4}) {
System.out.println(i);
}
假如使用Java8,我们只需要一行代码
Arrays.stream(new int[]{1, 2, 3, 4}).forEach(System.out::println);
我们只需要定义一个函数,其他的Stream
帮我们解决
Stream模型 #
简单来说Stream
把操作分为两张,一种是中间操作,一种是终结操作
中间操作你可以把他看做对数据源的一种处理,而终结操作是定义产生新数据过程,简单来说,假如我们有一堆苹果
需要处理,我们使用一个流水线来对经过的苹果进行各种处理(中间操作),丢掉烂掉的(filter),削掉皮(map)等等,
最后的我们需要对苹果进行装箱(终结操作)
分析功能 #
我们接下来看看我们需要实现的功能,就是去重,我们知道Stream
其实提供了一个distinct
方法中间操作来帮我们实现去重功能,
对于基本类型比如String
,Integer
,Long
这些我们能很容易进行去重,但是对于复杂类,我们得
重写hashCode
和equal
方法来支持去重操作了,对于集合内的每个数据都会用equal
来进行去重
接下来我们尝试直接使用终结操作collect
来解决掉
怎么做呢,collect
其实也很简单就是创建一个容器,把数据装进去,我们就只需要使用一个可以支持去重操作的
容器来做就好了
支持去重的有Map
和Set
,所以我们想到的第一个方法就是将流变成一个Set
,这个也是网上很多人提供的一个版本
dishes.stream().distinct().collect(Collectors.toCollection(
() -> new TreeSet<>(Comparator.comparing(Dish::getType)))
我们把这行代码给分解成两行
TreeSet<Dish> container = new TreeSet<>(Comparator.comparing(Dish::getType));
dishes.stream().collect(Collectors.toCollection(() -> container));
第一行其实就是声明了一个容器,核心代码就是 () -> container
我们传入一个容器,让他来存贮,我们使用
TreeSet
的一个构造器,它只需要传入一个函数,他会比较传进来的每个值,假如发现已经存在了它就不会插入了
但是这个有个问题就是,他只能选择第一个出现的
接下来我们试试用Map
,
dishes.stream().collect(toMap(Dish::getType, d -> d);
我们写下下面的代码,但是这个代码有点问题就是假如出现重复的,他会抛异常,因为程序默认不知道你想要哪个数据
dishes.stream().collect(toMap(Dish::getType, d -> d, (oldData, newData) -> oldData));
我们可以传入一个选择函数,这样当发现重复的时候就可以选择要哪个插入到map中去,这个也解决了上面使用Set
来存贮的时候没法选择到底是新来的还是后来的
总结 #
这篇博客简单的介绍了实现去重功能的三种实现方法,接下来这个系列的博客会深入到源码来探究Java8如何实现
Stream这么多功能的