如何避免 Lombok 的常见陷阱?

更新时间 2023-07-29 16:24:47

一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...点击查看项目介绍 ;
  • 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;

截止目前, 星球 内专栏累计输出 54w+ 字,讲解图 2476+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 1900+ 小伙伴加入学习 ,欢迎点击围观

尽管 Lombok 是一个强大的工具,可以帮助我们简化代码,提高开发效率,但是如果不恰当地使用,也可能会引入一些问题。本文将为你详述如何避免 Lombok 的常见陷阱。

1. 慎用 @Data

@Data 是一个实用的注解,它包含了 @Getter@Setter@ToString@EqualsAndHashCode@RequiredArgsConstructor。这在一般情况下非常方便,但是当你需要自定义一些方法时,就可能会遇到问题。

例如,你可能需要自定义 equalshashCode 方法,但是由于 @Data 注解自动生成了这些方法,所以你的自定义方法会被覆盖。为了避免这种情况,你可以使用 @EqualsAndHashCodecallSuper 属性。

@EqualsAndHashCode(callSuper = true)
public class MyEntity extends BaseEntity {
    //...
}

这样做可以确保父类的 equalshashCode 方法也被调用。

此外,@Data 注解也会生成所有字段的 getter 和 setter 方法,如果你的字段中包含了一些不应该被外部访问或修改的数据,这可能会导致问题。在这种情况下,你可以使用 @Getter(AccessLevel.NONE)@Setter(AccessLevel.NONE) 来禁止生成特定字段的 getter 和 setter 方法。

@Data
public class MyEntity {
    @Getter(AccessLevel.NONE)
    private String sensitiveData;
    //...
}

2. 注意 @ToString 的循环引用问题

@ToString 注解非常实用,但是在处理含有循环引用的数据结构时,必须要小心。例如,你有一个双向链表或者一个树形结构,其中的元素互相引用。这样的话,当你调用 toString 方法时,就可能会出现无限循环的情况,最后导致栈溢出。为了避免这种情况,你可以使用 @ToString.Exclude 注解来排除掉会导致循环引用的字段。

public class TreeNode {
    private TreeNode parent;
    private TreeNode child;

    @ToString.Exclude
    public TreeNode getParent() {
        return parent;
    }

    //...
}

3. @EqualsAndHashCode 与懒加载

当你使用 JPA 或 Hibernate 这样的 ORM 框架时,你可能会使用到懒加载(Lazy Loading)特性。这意味着,某些字段在第一次被访问时才会被加载。而如果你在这样的字段上使用了 @EqualsAndHashCode 注解,可能会在你并不希望加载这些字段的情况下触发它们的加载。

为了避免这种情况,你可以使用 @EqualsAndHashCode(onlyExplicitlyIncluded = true),然后在你想要包含在 equalshashCode 方法中的字段上使用 @EqualsAndHashCode.Include

@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class MyEntity {
    @EqualsAndHashCode.Include
    private Long id;

    @OneToMany
    private List<MyOtherEntity> otherEntities;

    //...
}

在这个例子中,otherEntities 字段不会被包含在 equalshashCode 方法中,所以在计算这些方法时,不会触发它的加载。

4. 小心 @SneakyThrows

@SneakyThrows 是一个非常有用的注解,它可以让你 "偷偷" 抛出受检异常,而无需在方法签名中声明它们。但是这也可能会引起一些问题。

首先,你的代码的调用者可能并不知道你的方法可能会抛出哪些受检异常,这可能会导致他们在处理异常时疏忽。为了解决这个问题,你应该在你的方法的文档注释中明确说明可能会抛出哪些异常。

其次,@SneakyThrows 会将受检异常包装在 RuntimeException 中抛出,如果你的代码的调用者捕获了 RuntimeException,并且没有检查它的原因,那么他们可能会错过受检异常。为了解决这个问题,你应该尽量避免在你的方法中直接抛出 RuntimeException,而是应该抛出具体的异常类型。

5. 不要滥用 Lombok

虽然 Lombok 的注解可以极大地简化我们的代码,但是这并不意味着我们应该在所有地方都使用它。在一些情况下,手动编写代码可能会更好。

例如,你可能需要自定义某个字段的 getter 或 setter 方法,或者你需要自定义 equalshashCodetoString 方法。在这些情况下,使用 Lombok 的注解可能会导致你的自定义代码被覆盖。

此外,过度使用 Lombok 的注解也可能会使你的代码变得难以理解。你的同事或未来的你可能会对一些自动生成的方法感到困惑,例如,他们可能会不清楚某个方法是从哪里来的,或者为什么某个方法的行为和预期不一致。

因此,虽然 Lombok 是一个强大的工具,但是我们也需要明智地使用它。我们应该始终保持警惕,确保我们的代码不仅简洁,而且易于理解和维护。

总结

总的来说,Lombok 是一个非常有用的工具,在企业级开发中,它可以极大地提高我们的开发效率,除非有自定义的情况,需要谨慎处理外,它是利大于弊的存在。