• 集合数据丢失distinct与EqualsAndHashCode的Bug问题


    Java8中stream流distinct与EqualsAndHashCode的Bug问题

    在前面一篇文章 equals和hashCode的暗操作 中,我们指出,只要重写 equals,就必须重写 hashCode方法,也举了例子,在HashSet中去重失效的问题。

    现在,我们就来看看真实业务上遇到的equals和hashCode引起的bug,实际上也是个去重的问题,引起了集合数据丢失。

    主要涉及到,两个知识,

    • 一个是JDK8中stream流的distinct方法。
    • 一个是 Lombok的@Data、@EqualsAndHashCode的使用细节。

    问题回顾

    在一次公用平台的问题反馈中,用户服务的 queryUserListByRoleNames 接口,丢失数据,从数据库查询发现

    在这里插入图片描述
    本接口排除了七条数据,不知道这七条为啥被排除?

    排查发现

    查看代码,通过Debug发现,查询的确是查到了16条数据,只是最后一步,加了个distinct去重,就丢失了7条数据,但是这7条数据并不跟其他数据冲突,也没有重复,为什么会被过滤掉了呢?
    在这里插入图片描述
    找到 List userDtoList = new ArrayList<>(); 代码中对应的实体类UserDto。
    在这里插入图片描述
    我们这个类UserDto,继承了基础类BaseUser,且引入注解:@EqualsAndHashCode(callSuper = false) ,这是什么意思?

    @EqualsAndHashCode 注解

    不扯太多废话了,意思就是,EqualsAndHashCode注解是来自于lombok的。

    其中 @EqualsAndHashCode注解:在JavaBean或类JavaBean中使用时,会自动重写实体的equals方法和hashCode方法。

    需要注意的点是:属性 callSuper。
    属性 callSuper的作用:在重写hashcode()和equals()方法时决定是否调用父类的属性。默认就是false。
    比如callSuper = false:表示会在对象比较时不考虑父类中的成员,仅仅比较子类中的属性就判断是否相同。

    说白了,就是当我们用于对象属性比较时,只比较子类的属性,也就是讲: 如果两个对象子类属性一致,就算父类属性不一致,在比较时也会出现两个对象是相同的,返回的true这样的结论。”

    那么问题就来了,class UserDto extends BaseUser ,父类BaseUser中,包含了关键字段,但却是被忽略的。
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/df6a484d8f964866b16b64c9beb88919.png
    而UserDto 中,都是一些附加字段,比如sex、phone等等。

    在案例中,对象是:

    UserDto(sex=0, userId=10070, account="lt3",userName="李婷3")
    UserDto(sex=1, userId=10071, account="lt4",userName="李婷4")
    UserDto(sex=0, userId=10072, account="lt5",userName="李婷5")
    
    distinct 方法的使用注意

    distinct 方法是根据 hashcode 和 equal 方法去判定是否是同一个元素的,底层也是HashSet方式来实现去重。所以,在使用distinct 方法前,一定要重写 对象类的 hashcode 和 equals 方法

    具体可以看源码,stream接口,

  • 相关阅读:
    初识SpringBoot
    Django(四、路由层)
    【服务器搭建】教程一:没钱买服务器怎么玩 进来看
    EasyNLP发布融合语言学和事实知识的中文预训练模型CKBERT
    C++之类型转换
    Tomcat
    Django render()函数页面渲染
    【K8S系列】深入解析k8s网络插件—Cilium
    C语言 二叉树
    es示例。。。
  • 原文地址:https://blog.csdn.net/ITBigGod/article/details/126956003