Stream distinct根据list某个字段去重的解决方案
作者:@大吉 发布时间:2022-06-22 22:23:26
标签:Stream,distinct,去重
需求:
List<UserPojo> users = new ArrayList<>();
//第一个user和第4个user应该是相等的,因为它们的name和address相等
//id name address age
users.add(new UserPojo(1, "daji", "山东省青岛市", 19));
users.add(new UserPojo(2, "daji2", "山东省济南市", 20));
users.add(new UserPojo(3, "daji3", "北京市", 22));
users.add(new UserPojo(4, "daji, "山东省青岛市", 23));
上面有4个user,对其进行去重,去重逻辑是根据name字段和address字段来决定(name和address字段相等 ,即可判定这两个对象相等,不必关心其他字段是否相等)
因此:第一个user和第4个user应该是相等的,因为它们的name和address相等
解决方案
stream的distinct去重方法,是根据 Object.equals,和 Object.hashCode这两个方法来判断是否重复的。
所以我们可以利用这个特性 ,重写pojo的 Object.equals,和 Object.hashCode这两个方法,来实现。
1、重写Object.equals方法
@Override
public boolean equals(Object o) {
UserPojo thisPojo = (UserPojo) o;
//只有name 和 address 相等,也算相等
if (this.getName().equals(thisPojo.getName()) && this.getAddress().equals(thisPojo.getAddress())){
return true;
}else {
return false;
}
}
2、重写Object.hashCode方法
重写hashCode需要根据你选择的字段重新计算。
本例就是根据name和address重新计算hashcode。规则如下图:
最终方法:
@Override
public int hashCode() {
//根据name和address重新计算hashcode
int result = getName().hashCode();
//17是死值, jdk建议用17
result = 17 * result + getAddress().hashCode();
return result;
}
3、使用distinct去重:
users = users.stream().distinct().collect(Collectors.toList());
结果(去重成功,去掉了一个重复值):
问题到此成功解决
4、[可选方案] 继承pojo重写equals和hashcode
如果我们不想动原有的pojo,我们可以新建一个新的pojo,来继承原有的pojo。
1、 新建一个子类,继承UserPojo
2、 重写该子类的 equals方法和hashcode 方法
3、 将父类的全部数据灌入子类,对子类 使用stream的distinct去重
代码如下:
@Test
void test15() {
List<UserPojo> users = new ArrayList<>();
//第一个user和第4个user应该是相等的,因为它们的name和address相等
users.add(new UserPojo(1, "daji", "山东省青岛市", 19));
users.add(new UserPojo(2, "daji2", "山东省济南市", 20));
users.add(new UserPojo(3, "daji3", "北京市", 22));
users.add(new UserPojo(4, "daji", "山东省青岛市", 23));
/*
解决方案:使用stream的distinct去重
1、 新建一个子类,继承UserPojo
2、 重写该子类的 equals方法和hashcode 方法
3、 将父类的全部数据灌入子类,对子类 使用stream的distinct去重
*/
List<OverrideEqualsPojo> overrideEqualsPojos = new ArrayList<>();
for (UserPojo user : users) {
OverrideEqualsPojo overrideEqualsPojo = new OverrideEqualsPojo();
BeanUtils.copyProperties(user,overrideEqualsPojo);
overrideEqualsPojos.add(overrideEqualsPojo);
}
overrideEqualsPojos = overrideEqualsPojos.stream().distinct().collect(Collectors.toList());
System.out.println(overrideEqualsPojos);
}
子类pojo代码:
package com.daji.stream;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Objects;
public class OverrideEqualsPojo extends UserPojo{
public OverrideEqualsPojo(int id, String name, String address, int age) {
super(id, name, address, age);
}
public OverrideEqualsPojo() {
}
@Override
public boolean equals(Object o) {
OverrideEqualsPojo thisPojo = (OverrideEqualsPojo) o;
//只有name 和 address 相等,也算相等
if (this.getName().equals(thisPojo.getName()) && this.getAddress().equals(thisPojo.getAddress())){
return true;
}else {
return false;
}
}
@Override
public int hashCode() {
//根据name和address重新计算hashcode
int result = getName().hashCode();
//17是死值, jdk建议用17
result = 17 * result + getAddress().hashCode();
return result;
}
}
来源:https://blog.csdn.net/weixin_44757863/article/details/125659749


猜你喜欢
- 在java开发的实际场景中,我们经常要对时间进行格式化处理,但是每次获取开发中自己需要的格式都要重新写一个方法,这样的代码看起来是非常的笨重
- 一.递归方法1.递归就是自己调用本身的方法,前提是有方法。2.递归使用找出递归的规律递归要有出口条件,也就是结束条件3.注意事项递归次数不能
- 相信很多人都了解c#语言,但是对于c#语言编写应用程序的经验不够多,所以经常为没有实例练习而烦恼吧。今天小编给大家介绍下C#里的多线程技术。
- 本文实例讲述了Android使用ActionBar和ViewPager切换页面,分享给大家供大家参考。具体如下:运行效果截图如下:项目布局如
- 问题线上程序出现了OOM,程序日志中的输出为Exception in thread "http-nio-8080-exec-102
- Handler每个初学Android开发的都绕不开Handler这个“坎”,为什么说是个坎呢,首先这是Android架构的精髓之一,其次大部
- 1、这个方法在GpsNET.JT809Core里来源:https://www.cnblogs.com/cnsend/p/12197982.h
- 最近这段时间一直在看Android,利用Listview去实现点赞功能,下面给大家介绍下基本思路。基本思路:进入界面–》获取数据–》 在Li
- Java与C++实现相同的MD5加密算法1、Java版package com.lyz.utils.common;import java.io
- 和之前一样首先看一下WPF钟表效果图 是不是很炫酷,上面的那个花都是带有动画效果的图片 。接下来就是代码了。首先看一下整个场景的布局搭建&l
- 1. 布局: GridBagLayout官方JavaDocsApi: java.awt.GridBagLayoutGridBagLayout
- 本文实例讲述了Android学习笔记之应用单元测试。分享给大家供大家参考,具体如下:第一步:在AndroidManifest.xml中加入如
- 前言AQS 绝对是JUC的重要基石,也是面试中经常被问到的,所以我们要搞清楚这个AQS到底是什么?骑工作原理是什么?AQS是什么?AQS,A
- 什么原因使我们不得不使用线程池?个人认为主要原因是:短时间内需要处理的任务数量很多使用线程池的好处:1.减少在创建和销毁线程上所花的时间以及
- java 算法之归并排序详解一、思想 归并排序:将一个数组排序,可以先(递归地)将它分成两半部份分别排序,然后将结果归并起来; &
- JAVA操作XML文档主要有四种方式,分别是DOM、SAX、JDOM和DOM4J,DOM和SAX是官方提供的,而JDOM和DOM4J则是引用
- 本文实例为大家分享C++二分查找算法,通过改变边界位置来进行查找的方法,代码如下:#include <iostream>usin
- 本文先为大家介绍如何利用缓存Cache方便地实现此功能。 Cache与Session这二个状态对像的其中有一个不同之处,Cache是一个全局
- C# winform 新手实例:点击生成二维码效果图如下:打开exe默认界面部分代码://button点击事件private void bu
- 前言本文主要给大家介绍了关于Spring Boot优化内嵌Tomcat的相关内容,分享出来供大家参考学习,下面话不多说了,来一看看详细的介绍