跳过正文
  1. 博客/
  2. 后端/
  3. 框架/

Stream源码(1):如何实现去重

·3 分钟· ·
后端 框架 Java Stream
目录

本篇博客是在看代码的时候看到使用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方法中间操作来帮我们实现去重功能,
对于基本类型比如StringIntegerLong这些我们能很容易进行去重,但是对于复杂类,我们得
重写hashCodeequal方法来支持去重操作了,对于集合内的每个数据都会用equal来进行去重

接下来我们尝试直接使用终结操作collect来解决掉
怎么做呢,collect其实也很简单就是创建一个容器,把数据装进去,我们就只需要使用一个可以支持去重操作的
容器来做就好了

支持去重的有MapSet,所以我们想到的第一个方法就是将流变成一个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这么多功能的

引用
#

相关文章

Java的char类型到底几个字节
·6 分钟
后端 框架 Java
引言 # 之所以有这个疑问,是上次阅读Java基础书时碰到讲解char类型没有看明白,并且在代码验证过程中错误的理解了代码的意思,导致我对这么个简单问题产生疑惑并且“恶意揣测”Java内部的黑魔法,这里就把我如何走上歪路,并且最终找到“正确”的道路的故事讲出来
Dubbo浅探
·3 分钟
后端 框架 Java Dubbo
繁忙的一周终于过去了,加入小影第一周主要是熟悉后端架构,同事们都挺好,自己的基础还是有点弱,前段时间简单的把Spring Cloud 和 Dubbo学习了一下,但是其实对于工作来说,之前学的都是最新的版本,但是其实公司用的版本很老了,所以需要时间去学习老版本
Spring Cloud Alibaba浅探
·2 分钟
后端 框架 Java SpringBoot
花了半天时间把Spring Cloud Alibaba 的Nacos 、 Sentinel 和 Seata简单的使用了一下,下面是我的一些看法
SpringCloud浅析
·5 分钟
后端 框架 Java SpringBoot
最近在学SpringCloud,之前一直对用视频学嗤之以鼻,觉得只有弱者才会这样,但是其实对于一些已经非常常见的技术 比如SpringCloud这种,已经出来很长一段时间了,而且其实非常杂,用视频学起来其实非常快,当然前提是你要三倍速播放,而且 你得把视频配套的代码找到,这样你就能很快的掌握这个。
如何在Ubuntu上发布Scala Jar包到Maven中央仓库
·7 分钟
后端 框架 Java
由于网上的教程大多数是Windows下的,而且都是介绍怎么打包Java的Jar包,关于Scala相关的比较少,因此我踩了不少坑才成功的把包发布到Maven中央仓库,你们可以才中央仓库里面搜到我的包
浅析Spring
·3 分钟
后端 框架 Java SpringBoot
 > Spring核心就是IoC(依赖注入)AoP(面向切面)本篇就基于一个开源项目 tiny-spring 来分析Spring框架到底给我们提供了什么东西