• List对象集合根据组合属性进行差集运算


    背景

       当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会将原数据集合改变。

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

  • 相关阅读:
    php基础之简单运算
    选择平淡
    php基础之控制结构
    关于三元运算符的初步应用及理解
    VS2015 遇到异常。这可能是由某个扩展导致的
    C#中如何去除窗体默认的关闭按钮
    (转载)SQL基础--> 约束(CONSTRAINT)
    SQL Server安装后设置SQL Server验证登录
    附加数据库 对于 ""失败,无法打开物理文件 操作系统错误 5:拒绝访问 SQL Sever
    SQL Server数据库操作(二)
  • 原文地址:https://www.cnblogs.com/xuanhaoo/p/14335365.html
Copyright © 2020-2023  润新知