背景

   当List是一个基本数据类型的集合的时候,进行集合运算还比较方便,但是有这么一些业务场景,比如某个用户权限变化的列表,或者取数据的变化结果,当时有时候用笨方法多循环两次也是可以的,只不过代码显得比较复杂,而且性能也不会太好。这次迭代我也就遇到这么一个需求。

实现

   场景:我们系统用户是四个维度这样的数据,我们需要保存这样的数据,提供给前端一个这样的接口,前端传递用户相应的数据(用户组|职位|部门|用户),但是前端不会告诉我们,哪些是新增的,哪些是删除的,还有哪些没有变化,反正数据一股脑的给你,后端来自己组织。​当然,一般第一想法都是循环嘛,但是我一般的习惯都是将这种处理方法放在最后一个备选,实在想不出来好的方式才会使用最简单粗暴的方式哈哈哈。而且这个地方是要根据实体类里面的两个字段一起判断,无形中增加复杂度。List可以这样求差集(交并集类似):

// 差集
List<String> subList = list1.stream().filter(item -> list2.contains(item)).collect(toList());

   但这个List就一个String类型的,方便,而我们要判断的是两个对象是不是相等,简单嘛,一样这样使用嘛,那万一两个对象并不相同的,比如一个列表是从数据库中取出来的值,一个传出来的,它们的字段值都不同,那他们equals肯定也不同的,过滤后的值也不同,就会造成数据错误。

// 考虑过滤数据,不进行重复更新
List<SaveLibUserParam> saveLibUserParamList = param.getSaveLibUserParamList();
List<UserCourseLibraryManage> originSaveList = Lists.newArrayList();
if (Objects.nonNull(saveLibUserParamList) && saveLibUserParamList.size() > 0) {
originSaveList = BeanConvertUtils.convertList(saveLibUserParamList, UserCourseLibraryManage.class);
}
// 查询出本来的旧数据
List<UserCourseLibraryManage> list = userCourseLibraryManageDao.queryListByCompanyId(companyId);
log.info("originList:{}", originSaveList);
log.info("list:{}", list);
// 需要本次新增的,即在origin中而list没有的
// 需要本次删除的,即在origin没有而list中有的
List<UserCourseLibraryManage> needAddList = originSaveList.stream().filter(item -> !list.contains(item)).collect(Collectors.toList());
List<UserCourseLibraryManage> finalOriginSaveList = originSaveList;
List<UserCourseLibraryManage> deleteList = list.stream().filter(item -> !finalOriginSaveList.contains(item)).collect(Collectors.toList());
log.info("needAddList:size:{}, data:{}", needAddList.size(), needAddList);
log.info("deleteList:size:{}, data:{}", deleteList.size(), deleteList);

   所以要考虑判断两个对象相等的条件,这里大家应该都知道了,就是重写equals方法,判断对象中值相等用equals方法,不用用\(==\)符号,\(==\)符号在判断对象类型时判断的是地址,这个地方需要注意的。对上面的UserCourseLibraryManage实体对象进行重写equals,在重写equals的时候,一定要注意:hashCode一般也建议重写,以保证两个对象的hash值一致,只有当对象的hash值一致时,系统才会判定这两个对象相等。重写hashcode的时候为什么用17,网上说好像Jdk就用的17,还有待考证,反正保证不要超出int范围就可以。

/**
* 重写equals方法
* @param obj
* @return
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof UserCourseLibraryManage) {
if (Objects.equals(((UserCourseLibraryManage) obj).dataType, this.dataType)
&& Objects.equals(((UserCourseLibraryManage) obj).dataId, this.dataId)) {
// System.out.println("相同对象:obj:"+obj+", this:{}"+this+"");
return true;
} else {
return false;
}
} else {
return super.equals(obj);
}
} /**
* 重写hashcode
* @return
*/
@Override
public int hashCode() {
int newHashCode = dataType.hashCode();
newHashCode = 17 * newHashCode + dataId.hashCode();
return newHashCode;
}

   这样处理了一番过后,过滤处理后的数据就是我们想要的数据,达到了目的,并且性能也肯定得到了提升,使用的java8的流处理。

tips:上面list.stream处理的地方求差集用list自己的removeAll也是可以的。有兴趣的可以看下源码,但removeAll会将原数据集合改变。

   希望以后如果有小伙伴遇到这种问题,刚好不太了解如何处理,希望这个分享能有一定的帮助!

List对象集合根据组合属性进行差集运算的更多相关文章

  1. C# List 集合 交集、并集、差集、去重, 对象集合、 对象、引用类型、交并差补、List<T>

    关键词:C#  List 集合 交集.并集.差集.去重, 对象集合. 对象.引用类型.交并差.List<T> 有时候看官网文档是最高效的学习方式! 一.简单集合 Intersect 交集, ...

  2. C#高级知识点概要(3) - 特性、自动属性、对象集合初始化器、扩展方法、Lambda表达式和Linq查询

    1.特性(Attributes) 特性(Attributes),MSDN的定义是:公共语言运行时允许你添加类似关键字的描述声明,叫做attributes, 它对程序中的元素进行标注,如类型.字段.方法 ...

  3. C#3.0新特性:隐式类型、扩展方法、自动实现属性,对象/集合初始值设定、匿名类型、Lambda,Linq,表达式树、可选参数与命名参数

    一.隐式类型var 从 Visual C# 3.0 开始,在方法范围中声明的变量可以具有隐式类型var.隐式类型可以替代任何类型,编译器自动推断类型. 1.var类型的局部变量必须赋予初始值,包括匿名 ...

  4. Java List对象集合按对象属性分组、分组汇总、过滤等操作示例

    import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Col ...

  5. Stream流用于按照对象中某一属性来对集合去重+简单数据类型集合的去重

    上次对Stream流来进行分组的文章很多人看,想看的可以来这: Stream流来进行集合分组 这次小编又带来Stream的去重,话不多数,直接上代码: 这是对简单数据类型的去重 //字符串集合进行简单 ...

  6. 如何将List集合中相同属性的对象合并

    在实际的业务处理中,我们经常会碰到需要合并同一个集合内相同属性对象的情况,比如,同一个用户短时间内下的订单,我们需要将各个订单的金额合并成一个总金额.那么用lambda表达式和HashMap怎么分别处 ...

  7. 再谈使用Emit把Datatable转换为对象集合(List<T>)

    一.前因和存在的问题 前面我写了一篇<使用Emit把Datatable转换为对象集合(List<T>)>的博文,其实起源于我自己编写的一个orm工具(见前面几篇博文有介绍),里 ...

  8. 深入理解javascript对象系列第二篇——属性操作

    × 目录 [1]查询 [2]设置 [3]删除[4]继承 前面的话 对于对象来说,属性操作是绕不开的话题.类似于“增删改查”的基本操作,属性操作分为属性查询.属性设置.属性删除,还包括属性继承.本文是对 ...

  9. SQL中对于两个不同的表中的属性取差集except运算

    SQL中对两个集合取差集运算,使用except关键字,语法格式如下: SELECT column_name(s) FROM table_name1 EXCEPT SELECT column_name( ...

随机推荐

  1. java图像开发学习——JTable之导入数据库

    package demo; import java.awt.BorderLayout; import java.awt.Container; import java.awt.event.MouseAd ...

  2. 给2021年的我立几个FLAG

    看多了大牛的年终总结,我也懒得写了,反正写出来也没人看. 其实上面都是借口,我只是完全没有写年终总结的习惯. 为啥呢?因为这些年过的平平无奇,并没有什么特别出彩的事情. 如果有,嗯,2020年,我结婚 ...

  3. python实例:解决经典扑克牌游戏 -- 四张牌凑24点 (一)

    Hey! Hope you had a great day so far! 今天想和大家讨论的是一道我从这学期cs的期末考试得到灵感的题:Get 24 Poker Game.说到 Get 24 Pok ...

  4. Future.get(并发之从任务中产生返回值)

    import java.util.ArrayList; import java.util.List; import java.util.concurrent.Callable; import java ...

  5. springboot项目Invalid bound statement (not found): com.xxxx.dao.xxxDAO.xxx解决方法

    1.首先判断自己的Dao和mapper的对应关系,注意要一一对应的. 2.配置信息出现问题,注意配置信息填写: 3.记住要细心细心,细心,重要的事情说三遍.

  6. HTML学习案例--仿淘宝商品信息

    步骤:1.布局分析 2.敲代码 考察知识点: 1.类选择器(素材第四天) 2.CSS关于display,padding,margin的应用 3.如何用div布局 总结: 如果想让一行有两组以上的字块, ...

  7. [学习笔记]Golang--基础数据类型

    1,不同类型的变量不能互相赋值或者操作,如var a int8 = 16var b int = 23c := a + b 会报错,且int虽然默认32位,但和int32是不同的类型 iota只在声明枚 ...

  8. 杭电OJ:1089----1096(c++)(ACM入门第一步:所有的输入输出格式)

    1089:输入输出练习的A + B(I) 问题描述 您的任务是计算a + b. 太容易了?!当然!我专门为ACM初学者设计了这个问题. 您一定已经发现某些问题与此标题具有相同的名称,是的,所有这些问题 ...

  9. 3.k8s存储之ConfigMap、Secret

    1.ConfigMap ConfigMap 功能在 Kubernetes1.2 版本中引入,许多应用程序会从配置文件.命令行参数或环境变量中读取配置信息.ConfigMap API 给我们提供了向容器 ...

  10. Spring框架之jdbc源码完全解析

    Spring框架之jdbc源码完全解析 Spring JDBC抽象框架所带来的价值将在以下几个方面得以体现: 1.指定数据库连接参数 2.打开数据库连接 3.声明SQL语句 4.预编译并执行SQL语句 ...