记一次lombok踩坑记

引言

今天中午正在带着耳机遨游在代码的世界里,被运营在群里@了,气冲冲的反问我最近有删生产的用户数据的吗?我确定客气的回答道没有呀?生产的数据我怎么能随随便即可以删除,这但是公司的红线,再说了我也没有数据库的删除权限啊,不过查询权限仍是有的。赶忙登上堡垒机,而后去生产数据库查一下数据,查了一下数据是还在的,吓死了,数据还在问题就不大了,无非就是应用程序出问题了,赶忙打开代码查看下,为何会少了一条用户数据,看了下代码貌似没啥问题就是比较简单的一个逻辑,直接从DB经过分页查询数据给到前端,而后前端负责展现,没有啥复杂的逻辑。心想确定是前端的问题,确定是他少展现了数据,立马把问题也甩给了他,让他帮忙配合一块儿看看是不是前端的问题,而后本身也仔细看看代码,不到一分钟前端说他展现的数据没有问题,都是后端给到的,没有漏掉展现的。那就是后端的bug了罗。肉眼望去以为可能出问题的就是分页致使的数据丢了。不过这个分页插件是全公司都在用,应该不至于出问题把,找不到问题只能让测试帮忙在测试环境试试,看看是否能够复现。前端

测试环境复现

仔细看了一眼,竟然有个去重的方法,去重逻辑也比较简单就是把list经过转为set去下重,看下来应该就是这个去重方法有问题了
大体写了单元测试模仿了下生产的数据,大体逻辑以下:java

public static void main(String[] args) {
        Set<UserDTO> userSet = new HashSet<>();
        UserDTO userDTO = new UserDTO();
        userDTO.setId(1);
        userDTO.setUserName("java金融");

        UserDTO userDTO1 = new UserDTO();
        userDTO1.setId(2);
        userDTO1.setUserName("java金融");
        userSet.add(userDTO);
        userSet.add(userDTO1);
        System.out.println(userSet.size());
        System.out.println(userDTO1.equals(userDTO));
    }

    @Data
    static class UserDTO extends BaseDTO {
        private String userName;
    }
    @Data
    static class BaseDTO {
        private Integer id;
    }

咱们能够输出结果set集合的长度是1,user1user2 是相等的,明明两个userID是不同的,为什么会相等,咱们知道set能够去重
是由于Set的操做,都是经过操做map来实现的,setadd其实就是调用mapput方法,mapput方法我相信你们应该都去看过其源码,这里就不详细再说了,大概流程就是经过key经过hash算法定位到数组的下标,先判断keyhash是否相等,若是相等再去判断key的value相等,若是都相等就会覆盖原来的值。咱们上面这个例子就是对象的hashvalue都相等致使,可是咱们的两个对象user1user2 应该是不等的,由于ID不等,那为何会相等列?咱们仔细看下上面的代码,咱们使用了lombok里面@Data注解,咱们能够看看这个注解帮咱们生成了哪些方法
在这里插入图片描述
在这里插入图片描述
经过上面的对比咱们能够看出@Data注解帮咱们生成了 注在类上,提供类的get、set、equals、hashCode、canEqual、toString方法,这个注解确实比较方便。上面那个bug 就是由于它生成的equals方法有问题,咱们能够把上述代码编译下,而后把class 里面生成的equals方法拷贝出来看看
在这里插入图片描述面试

经过上述生成的代码咱们能够看出equals方法只比较了userName这个字段,也就是当前类的字段,并无去比较父类的字段,这就是致使两个对象相等的缘由,咱们既然找到问题了,那解决问题就比较简单。算法

解决问题

  • 手动重写equalshashCode方法,这种方法确定是不推荐的,咱们既然用了lombok就是为了解放咱们的双手,是代码变得更加简洁。
  • 在比较的类上加上@EqualsAndHashCode(callSuper = true) callSuper = true 会包含父类的equalshashCode方法
    咱们能够对比下加上@EqualsAndHashCode(callSuper = true)和没有加上这个注解生成的equals方法的代码差别。
    在这里插入图片描述
    差别点仍是很明显的,加入了@EqualsAndHashCode(callSuper = true) 会去调用父类的equals方法比较,因此这个注解也可以解决这个问题。
  • 这样加上注解确实能够解决问题,可是每一个类上面都要加上这个注解,这也是个体力活。咱们能够再找找其余的方案,例若有没有好比配置文件设置下什么的,而后就能全局生效了。最终经过查询资料发现咱们咱们写一个lombok.config的配置文件放在咱们项目的根目录下面,内容写上lombok.equalsAndHashCode.callSuper = call效果等同于@EqualsAndHashCode(callSuper = true),这样的话咱们就不须要为每一个类都去加上这个注释了,至关于在这个项目下面只要用到了@Data注解的类都会为其加上@EqualsAndHashCode(callSuper = true)经过配置文件的方式就能够全局生效。

总结

  • 咱们再来回顾下上面的问题,归根结底仍是因为对象的equals方法使用不当引发的,因此咱们在若是在判断自定义对象业务判断相等的时候须要去重写下hashCodeequals方法,重写的时候咱们能够经过idea来生成,生成后最好仍是去看一眼,看看生成的是否符合咱们的业务要求。数据库

  • 咱们在工做中操做一些常见的容器类好比Set、Map等来实现一些咱们本身的业务,咱们仍是有必要去看看它们的源码的,就好比咱们经过Set来进行去重,若是咱们是使用的自定义对象的话,若是没有重写hashCodeequals方法的话,去重就会去不成功,咱们只有了解了它,才能真正的去用好它。在关于hashCodeequals 阿里巴巴开发手册也有明确的说到
    在这里插入图片描述后端

  • lombok 用起来仍是挺爽的,可是仍是有一些细节须要稍微注意下。使用前能够大概的去看看它的官网提供的内容,否则出现莫名其妙的问题你都不知道如何下手。这个就有点相似于咱们使用SpringBoot同样,用起来很是爽,可是若是遇到莫名其妙的bug解决起来就比较头疼。数组

  • 最后咱们再来回顾几道关于hashCodeequals的比较常见的面试题?其实若是咱们只要真正看过HashMap的源码的话,这下面几个面试题仍是很是简单的。
    什么状况下须要咱们去重写 方法?
    若是只重写equals方法不重写HashCode能够吗?
    equals ,== 和hashcode()的区别?ide

单元测试

结束

  • 因为本身才疏学浅,不免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。
  • 若是你以为文章还不错,你的转发、分享、赞扬、点赞、留言就是对我最大的鼓励。
  • 感谢您的阅读,十分欢迎并感谢您的关注。
相关文章
相关标签/搜索