背景

   当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. idea中surround with

    idea中的surround with是把选中的代码块装进一些带有{}的语句中,比如if,try,for等等 快捷键是ctrl+alt+t,先选中代码,再按快捷键,如图

  2. windows下用pip安装库,出现Command "python setup.py egg_info"错误信息

    转自:http://blog.csdn.net/u011092188/article/details/64123561 解决方案: python -m pip install --upgrade -- ...

  3. Java学习日报7.23

    import java.util.Scanner;public class LandP {public static void main(String args[]) { System.out.pri ...

  4. 单细胞分析实录(2): 使用Cell Ranger得到表达矩阵

    Cell Ranger是一个"傻瓜"软件,你只需提供原始的fastq文件,它就会返回feature-barcode表达矩阵.为啥不说是gene-cell,举个例子,cell has ...

  5. Java8的Optional:如何干掉空指针?

    目录 Optional概述 Optional简单案例 Optional的主要方法 参考阅读 Optional概述 Optional 是个容器:它可以保存类型T的value,或者仅仅保存null.Opt ...

  6. WPF Line 的颜色过度动画

    <Line Grid.Column="2" Grid.ColumnSpan="2" VerticalAlignment="Center" ...

  7. 【渲染引擎】Blender的2021年最佳渲染引擎(上)

    Blender最终摆脱了"古怪的孩子"的装束,并穿上了更为严肃和受人尊敬的" 3D强者". 它已在业界获得广泛认可,许多工作室和艺术家正在将其纳入他们的产品线. ...

  8. Spring的自动装配与依赖注入

    Spring的自动装配与依赖注入 装配 = 创建Bean + 注入Bean 创建Bean 自动发现 显式注册Bean 注入Bean 基于配置的注入 自动注入 Spring的装配分为显式装配和隐式装配, ...

  9. LeetCode141-环形链表检测

    题目 给定一个链表,判断链表中是否有环. 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置 ...

  10. 解决Establishing SSL connection without server‘s identity verification is not recommended.

    每次从数据库中进行查询或者其他操作控制台都会出现以下警告,虽说不是error,但是很显眼.. WARN: Establishing SSL connection without server's id ...