背景

   当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学习日报7.8

    public class 定义要求文件名和类名保持一致,一个*.Java文件只允许有一个public class定义! 主方法是一切程序的起点, public static void main(Str ...

  2. java内置锁实现锁住代码块方案(同一个对象或锁住整个类.class)

    我们看一个例子: class Demo { public synchronized void test() { System.out.println("test方法开始执行,当前线程为:&q ...

  3. javascript 匿名函数的理解(转)

    原网址 http://www.jb51.net/article/21948.htm javascript 匿名函数的理解(透彻版) 代码如下: (function(){ //这里忽略jQuery所有实 ...

  4. Spark Streaming和Kafka整合是如何保证数据零丢失

    转载:https://www.iteblog.com/archives/1591.html 当我们正确地部署好Spark Streaming,我们就可以使用Spark Streaming提供的零数据丢 ...

  5. Logstash学习之路(一)Logstash的安装

    一.Logstash简介 Logstash 是一个实时数据收集引擎,可收集各类型数据并对其进行分析,过滤和归纳.按照自己条件分析过滤出符合数据导入到可视化界面.它可以实现多样化的数据源数据全量或增量传 ...

  6. 风炫安全Web安全学习第十节课 数字型的Sql注入

    数字型的Sql注入 风炫安全Web安全学习第十一节课 字符型和搜索型的sql注入 风炫安全Web安全学习第十二节课 mysql报错函数注入 风炫安全Web安全学习第十三节课 CUD类型的sql注入 风 ...

  7. Linux 设置静态IP

    由于工作需要,安装一套Linux系统.安装完成后发现这个家伙居然不能上网,然后看了下IP,(命令 ip a)发现是127.0.0.1 下面是我的界面: inet 是127.0.0.1/8 还有6个网卡 ...

  8. Spring(1) --入门(IoC,AOP)

    说说你对spring的理解? Spring框架是一个轻量级的企业级开发的一站式解决方案,所谓一站式解决方案就是可以基于Spring解决Java EE开发的所有问题.Spring框架主要提供了IoC容器 ...

  9. Go 的定时任务模块 Cron 使用

    前言 新项目是Golang作为开发语言, 遇到了些新的坑, 也学到了新的知识, 收获颇丰 本章介绍在Go中使用Cron定时任务模块来实现逻辑 正文 在项目中, 我们往往需要定时执行一些逻辑, 举个例子 ...

  10. LeetCode235 二叉搜索树的最近公共祖先

    给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先. 百度百科中最近公共祖先的定义为:"对于有根树 T 的两个结点 p.q,最近公共祖先表示为一个结点 x,满足 x 是 p.q 的祖 ...