Stream按对象某属性去重的方案

2023-11-06

1.Collectors.collectingAndThen

  • 这是Stream中的一个收集器,相比普通的Collectors.toList、Collectors.groupingBy等收集器
  • Collectors.collectingAndThen还可以在收集之后进行某种操作
  • 多一个形参,用于写function函数(有入参有出参)

源码分析

举例说明collectingAndThen:

List按某属性去重,返回List

例1

2.本质流程

使用Collectors.collectingAndThen的本质是:先把new Set( list ) 获取一个Set,然后new List ( set )返回List

3. 如何用Set去重

用TreeSet和HashSet都能去重,只是去重的逻辑不一样。先看二者的存储逻辑:

  • Hashset是通过复写hashCode()方法和equals()方法来保证的。
  • 而Treeset是通过Compareable接口的compareto方法来保证的。同理可以用Comparator来定制排序

3.1TreeSet去重

①自然排序Comparable接口

@Data
public class DtoReq implements Comparable {

 private String userName;
 private String password;
 
 @Override
 public int compareTo(Object o) {
  DtoReq req =  (DtoReq)o;
  return req.getUserName().compareTo(this.getUserName());
 }
}
  • 代码逻辑即:对userName字段进行比较,且TreeSet的去重功能不需要关注顺序,谁比谁都一样
  • 不过这种方式相当于写死了,耦合度太高

去重代码

ArrayList<DtoReq> collect = arrayList.stream().collect(
    Collectors.collectingAndThen(
        Collectors.toCollection(
            TreeSet::new),ArrayList::new)
);

new TreeSet(arrayList)时构造器会自动去比较Comparable接口的compareTo方法,而达到去重的效果

②定制排序Comparator接口

  • 当元素的类型没实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序

  • 应该用匿名对象重写compare方法 或用lambda表达式调用Comparator.comparing方法

    @Data
    public class DtoReq {

    private String userName;
    private String password;

    }

匿名对象重写compare方法

/**
 * 定制排序Comparator对象,封装了排序的逻辑
 * 这里的泛型千万不能省,会用作lambda表达式的类型推断
 */
Comparator<DtoReq> comparator = new Comparator() {
  @Override
  public int compare(Object o1, Object o2) {
    DtoReq r1 = (DtoReq)o1;
    DtoReq r2 = (DtoReq)o2;
    return r1.getUserName().compareTo(r2.getUserName());
  }

};

ArrayList<DtoReq> collect = arrayList.stream().collect(
    Collectors.collectingAndThen(
        Collectors.toCollection(
            () -> new TreeSet<>(comparator)
        )
        , ArrayList::new)
);

静态方法comparing+lambda表达式

不需要new那个Comparator对象并重写其compare方法,直接调用静态方法Comparator.comparing方法,其形参是方法引用,意为:针对某属性进行排序,当然这里不是为了排序,只是为了去重

ArrayList<DtoReq> collect = arrayList.stream().collect(
    Collectors.collectingAndThen(
        Collectors.toCollection(
            () -> new TreeSet<>(Comparator.comparing(DtoReq::getUserName))
        )
        , ArrayList::new)
);

3.2HashSet去重

  • 利用HashSet去重,只需要重写其equals()hashCode()方法
  • 而好巧不巧lombok的@data注解提供了这两个方法的重写

lombok引入@data

@Data
public class DtoReq {

 private String userName;
 private String password;

}

此时就已经有了equals()和hashCode()方法,直接用就好

直接调HashSet构造器

ArrayList<DtoReq> collect = arrayList.stream().collect(
    Collectors.collectingAndThen(
        Collectors.toCollection(
            () -> new HashSet<>()
        )
        , ArrayList::new)
);

方法引用进行优化

ArrayList<DtoReq> collect = arrayList.stream().collect(
    Collectors.collectingAndThen(
        Collectors.toCollection(
            HashSet::new) , ArrayList::new)
);

4.去重逻辑

5.为什么不用distinct()

Stream流有一个distinct()方法可以去重,但是这个distinct()是直接调用当前流中存储对象的equals()方法,而Set会计算哈希值
List去重以及效率分析

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Stream按对象某属性去重的方案 的相关文章

  • 使用 Maven 生成 Eclipse 项目文件

    当我尝试使用生成 Eclipse 项目文件时mvn eclipse eclipse我收到以下错误 插件管理器执行目标时出现内部错误 org apache maven plugins maven eclipse plugin 2 9 SNAP
  • Java 字符串哈希码缓存

    字符串不变性的优点之一是哈希码缓存以实现更快的访问 在这种情况下 如何处理具有相同哈希码的字符串的缓存 在这种情况下它真的能提高性能吗 在这种情况下 如何处理具有相同哈希码的字符串的缓存 被缓存的是字符串的哈希码 它被缓存在私有的int字符
  • Java中RandomAccessFile的并发

    我正在创建一个RandomAccessFile对象通过多个线程写入文件 在 SSD 上 每个线程都尝试在文件中的特定位置写入直接字节缓冲区 并且我确保线程写入的位置不会与另一个线程重叠 file getChannel write buffe
  • RxJava + Retrofit 2 的正确使用方法

    我有这样的 JSON success true data id 29 name u0420 u0435 u0441 u0442 u043e u0440 u0430 u0446 u0456 u044f u0411 u0430 u0447 u0
  • 如何实现具有LinkedHashMap类似功能的ConcurrentHashMap?

    我用过LinkedHashMap with accessOrdertrue 并同时允许最多 500 个条目作为数据的 LRU 缓存 但由于可扩展性问题 我想转向一些线程安全的替代方案 ConcurrentHashMap在这方面似乎不错 但缺
  • Active MQ - HelloWorld 示例异常

    我正在尝试运行 hello world 示例在这里找到 http activemq apache org hello world html I added activemq all 5 5 1 jar已经到图书馆了 它构建成功 但出现以下警
  • 如何为java注释处理器编写自动化单元测试?

    我正在尝试使用 java 注释处理器 我可以使用 JavaCompiler 编写集成测试 事实上我现在正在使用 hickory 我可以运行编译过程并分析输出 问题 即使我的注释处理器中没有任何代码 单个测试也会运行大约半秒 对于以 TDD
  • Android 游戏偶尔出现延迟

    我正在用 Java 制作一个简单的 Android 游戏 我注意到每 20 40 秒就会出现一些烦人的延迟 首先 我认为它们是由垃圾收集器引起的 但当我检查 LogCat 时 我发现游戏滞后时没有垃圾收集 每当游戏开始滞后时 我都会标记日志
  • 按文件名过滤 eclipse 中的警告

    我们使用 Eclipse 进行 Java 开发 并使用 Maven 将 JSP 编译成 servlet 以便在嵌入式 Jetty 实例中使用 这意味着要从 Eclipse 运行该项目 我必须包含 target jsp source 作为源文
  • 在java中将DataURL图像转换为图像文件

    我在我的 java servlet 中接收图像 DataURL 它看起来像 data image jpeg base64 9j 4AAQSkZJRgABAQAAAQABAA 我需要将其另存为图像文件 我该怎么做 The simplest w
  • spring mvc 跟踪引用页面

    在基于注释的弹簧控制器中 如果用户正在url com first page并点击一个链接或提交一份表格指出url com second page 如何制作second page知道url of first page所以这样second pa
  • 为什么我要使用责任链而不是 switch 语句

    考虑一下您已经获得了多次验证 仅当要检查的对象属于某种类型时 这些验证才应生效 为什么我要使用责任链而不是 switch 语句 责任链示例 public class Executor Inject private ValidatorFact
  • 反应式 Spring Webflux REST 控制器内部重定向

    我正在为 spring 反应项目创建简单的控制器服务器 在设置重定向到另一个位置时 我在调用时发现错误http localhost 8080 There was an unexpected error type Internal Serve
  • Java 不可变对象 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在学习不变性的概念 据我了解 一旦创建对象 不可变对象就无法更改其值 但我不明白不可变对象的以下用途 They are 自动是线程
  • Elasticsearch - EdgeNgram + 突出显示 + term_vector = 不好的突出显示

    当我使用带有edgengram min 3 max 7 front term vector with positions offsets的分析器时 文档包含文本 CouchDB 当我搜索 couc 时 我的亮点是 cpu 而不是 couc
  • Java LRU 缓存使用 LinkedList

    堆栈溢出的新手 所以请不要介意我以菜鸟的方式问这个问题 我正在尝试使用链表实现 LRU 缓存 我在这里看到了使用 linkedHashMap 和其他数据结构的其他实现 但对于这种情况 我正在尝试使用链表创建最佳优化版本 正如我在技术期间被问
  • 春季MVC。方法参数字段的默认值

    我有一个带有方法测试的简单控制器 RequestMapping produces application json ResponseBody public HttpEntity
  • 如何在速度模板中检索哈希图值

    如何从速度模板中的以下哈希图中检索值 请帮忙 LinkedHashMap
  • ASTParser:解析绑定后查找声明节点

    我创建了一个启用了绑定的 AST 当我稍后解析绑定时 我得到了一个有效的 ITypeBinding 但是 当我想要获取绑定的声明 Node 时 它 总是返回 null 除非 ITypeBinding 在 sourceFile 中声明 这是我
  • 构造函数参数和属性一起出现在 bean 定义中

随机推荐

  • win10 Jdk 版本切换

    环境信息 系统 Win 10 jdk 7 8 11 安装方式 可执行文件安装 exe 格式 切换步骤 1 jdk 安装后 一般我们会手动添加 JAVA HOME 系统环境变量 然后将 JAVA HOME bin 添加到系统环境变量 Path
  • 【计算机网络笔记】物理层:概念&传输媒体&传输方式

    传输媒体 用来传输数据 物理层 解决在各种传输媒体上传输比特01的问题 物理层给数据链路层提供传输透明比特流的服务 使数据链路层只需要考虑如何完成本层的协议和服务 而不必考虑网络的具体的传输媒体是什么 透明 数据链路层无需知道物理层是如何传
  • 一个类成员函数访问另一个类的私有成员方法(不依靠继承与友元),仅供娱乐 :XD

    class B class A public A double a 0 int b 0 y a x b cout lt lt A is creat lt lt endl A void show cout lt lt A y is lt lt
  • 7-7 12-24小时制 (15 分) (C语言实现)

    题目 思路 直接跟着题目往下写 没有过多思考 后面答案部分正确 才重新写了12点那里的程序 11min 代码 include
  • Java连接mysql数据库和oracle连接数据库驱动对比

    oracle安装复杂 占用空间大 很多人用了oracle之后就不用了 项目需要复现 如何实现 那就使用mysql数据库 mysql数据库安装和一般软件安装毫无区别 另外公司中最常用数据库文件就是保存整个的数据库的文件 这样可以进行不断的维护
  • 【环境配置】Windows10终端和VSCode下能够直接打开Anaconda-Prompt

    很多小伙伴在 Windows 下做深度学习开发的时候 遇到终端没有在 Linux 那么方便 那么我们现在就可以来设置一下 这样我们也可以在文件夹内部右键打开终端 也可以在 VS Code 里面新建一个虚拟环境的控制台 这里主要是针对 Ana
  • 嵌入式Linux入门指南(一)——学习路线篇

    嵌入式Linux入门指南 一 学习路线篇 摘要 文章介绍在Linux入门过程中的学习路线 必看书籍分享 1 开始学习实践Linux之前先清楚如何学习很重要 虽然条条大路通罗马 殊途同归 但是不同的路线要付出的代价 时间成本 显然差别巨大 总
  • C#GDI+编程基础(一:Graphics画布类)

    GDI 存在的意义 将变成与具体硬件实现细节分开 GDI 步骤 获取画布 绘制图像 处理图像 命名空间 using System Drawing 提供对GDI 基本图形功能的访问 using System Drawing Drawing2D
  • 5. Java数据类型

    数据类型 基本类型 整数类型 byte short int long 浮点类型 float double 字符类型 char String 布尔类型 true false public class demo2 public static v
  • 第十三届蓝桥杯Python 大学B组真题详解

    第十三届蓝桥杯Python B组真题详解 试题A 排列字母 试题B 寻找整数 试题C 纸张尺寸 试题D 位数排序 试题E 蜂巢 试题F 消除游戏 试题G 全排列的价值 试题H 技能升级 试题I 最长不下降子序列 最优清零方案 本届比赛 两道
  • 性能测试调优模型、思想和技术

    最近阅读 软件性能测试 分析与调优实践之路 一书 个人认为性能调优章节为整部书的精华 该章节包括了性能测试调优模型 调优思想和调优技术 下面是摘抄整理自书中内容 调优模型 下图为互联网中常见的用户请求的分层转发和处理的过程 在性能调优时就是
  • 5.5 综合案例1.0-电力采集

    综合案例 电力采集 1 简介 1 1 BL0939芯片 1 2 语音合成 1 3 注意事项 2 阿里云端设置 3 测试代码 main py app relay py app led py app elec py app audio py a
  • MySQL表的约束

    目录 约束 概念 分类 非空约束 not null 唯一约束 unique 主键约束 primary key 外键约束 foreign key 继续使用上篇文章https blog csdn net z714405489 article d
  • 94-----JS基础-----dom查询

    一 代码 同样很简单 但是下面的接口会比较常用 用到时具体看一下即可 主要是三个接口 1 document getElementById 2 document getElementsByTagName 3 document getEleme
  • (附源码)springboot学生宿舍管理系统 毕业设计 211955

    摘 要 科技进步的飞速发展引起人们日常生活的巨大变化 电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用 信息时代的到来已成为不可阻挡的时尚潮流 人类发展的历史正进入一个新时代 在现实运用中 应用软件的工作规则和开发步
  • Loguru 源码中如何sink参数是日志路径时,rotation不能精确到天

    当我们把日志一直不停写入某个文件中 那么这个文件可能会有几十上百 GB 显然这样是没有办法查看和检索的 所以我们需要一些方式来切分日志 例如 每个日志文件只有1GB 超过1GB 后 自动生成新的日志 又或者每天0点自动生成新的日志 当日志按
  • ROS与Arduino:Arduino IDE的配置安装+实现简单串口通讯

    rosserial arduino包可让ROS和ArduinoIDE一起工作 rosserial提供的ROS通讯协议工作在Arduino的UART上 它让Arduino成为标准的ROS节点 可以发布和订阅ROS消息 发布TF转换 获取ROS
  • WIN 10找不到IE浏览器&打不开IE浏览器&用户名自带“域”,怎么办?

    前言 因客户侧系统依赖安装VPN才能访问 客户发的证书安装文档 又依赖IE浏览器下进行 也试过其他浏览器总是卡在提交证书申请前的信息加载 所以开始找本机的IE浏览器 然而遇到的情况是这样的 1 总是跳转到Microsoft Edge 在这个
  • nuxt打包路劲问题_Nuxt最简入门,让vue项目快速被搜索引擎收录

    Nuxt js是vue js的通用框架 最常用的就是作ssr 一般的vue cli不利于搜索引擎的seo操作 但是nuxt很好的解决了这一大问题 Nuxt的优点 基于 Vue js 自动代码分层 服务端渲染 强大的路由功能 支持异步数据 静
  • Stream按对象某属性去重的方案

    1 Collectors collectingAndThen 这是Stream中的一个收集器 相比普通的Collectors toList Collectors groupingBy等收集器 Collectors collectingAnd