一不小心lombok就踩坑了

简介: 一不小心lombok就踩坑了

引言

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

测试环境复现

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

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()的区别?

结束

  • 由于自己才疏学浅,难免会有纰漏,假如你发现了错误的地方,还望留言给我指出来,我会对其加以修正。
  • 如果你觉得文章还不错,你的转发、分享、赞赏、点赞、留言就是对我最大的鼓励。
  • 感谢您的阅读,十分欢迎并感谢您的关注。
目录
相关文章
|
3月前
|
Java
lombok的使用
本文介绍了Lombok库的基本使用方法和常用注解,通过示例代码展示了如何使用Lombok简化Java对象的创建、属性访问、日志记录等编码工作,使代码更加简洁。
lombok的使用
|
3月前
|
IDE Java 编译器
lombok编译遇到“找不到符号的问题”
【9月更文挑战第18天】当使用 Lombok 遇到 “找不到符号” 的问题时,可能是由于 Lombok 未正确安装、编译器不支持、IDE 配置不当或项目构建工具配置错误。解决方法包括确认 Lombok 安装、编译器支持,配置 IDE 和检查构建工具配置。通过这些步骤通常可解决问题,若问题仍存在,建议检查项目配置和依赖,或查看日志获取更多信息。
1248 2
|
4月前
|
IDE Java 开发工具
Java 开发神器 Lombok:告别冗余,拥抱优雅!
Java 开发神器 Lombok:告别冗余,拥抱优雅!
78 0
|
6月前
|
安全 IDE Java
使用MapStruct和Lombok简化代码
使用MapStruct和Lombok简化代码
188 2
|
6月前
|
IDE Java 程序员
Lombok使用方法和总结
Lombok使用方法和总结
|
5月前
|
Java
@SneakyThrows 是 Lombok 库中的一个注解
`@SneakyThrows` 是 Lombok 库中的一个注解,它可以让你在方法签名中省略异常声明,而不需要显式地使用 try-catch 块来处理这些异常。当你使用 `@SneakyThrows` 注解时,Lombok 会自动生成相应的 try-catch 代码,将异常封装成运行时异常(通常是 `RuntimeException` 或其子类)。 这个注解在某些情况下可以简化代码,但请注意,它可能会隐藏潜在的问题,因为异常被转换成了运行时异常,这可能导致调用者无法正确处理这些异常。 下面是一个使用 `@SneakyThrows` 的示例: ```java import lombok.S
359 0
|
6月前
|
Java Maven Python
技术笔记:Lombok介绍、使用方法和总结
技术笔记:Lombok介绍、使用方法和总结
77 0
|
7月前
|
IDE Java 数据库连接
Lombok注解大全
这些是Lombok中的一些常见注解,它们可以显著减少Java代码中的冗余代码,提高代码的可读性和可维护性。不过,在使用Lombok之前,请确保你的开发环境已经配置好支持Lombok,通常需要安装相应的插件或进行设置以使IDE(如Eclipse、IntelliJ IDEA)能够正确解析Lombok注解。
57 4
|
7月前
|
IDE Java 数据库连接
Lombok注解大全
这些是Lombok中的一些常见注解,它们可以显著减少Java代码中的冗余代码,提高代码的可读性和可维护性。不过,在使用Lombok之前,请确保你的开发环境已经配置好支持Lombok,通常需要安装相应的插件或进行设置以使IDE(如Eclipse、IntelliJ IDEA)能够正确解析Lombok注解。
100 2
|
7月前
|
IDE Java 开发工具
Lombok 详解:简化 Java 开发的神奇工具
Lombok 是一款 Java 工具,通过注解自动处理如 getter/setter、toString、equals 和 hashCode 等常见代码,减少样板代码。安装 Lombok 需要在 IDE(如 IntelliJ IDEA)中添加插件,并在 Maven 或 Gradle 项目中配置依赖。常用注解包括 @Getter/@Setter 生成访问器,@ToString 生成对象描述,@EqualsAndHashCode 生成比较方法,@NoArgsConstructor/@AllArgsConstructor 生成构造器,@Data 综合应用这些注解。
414 9