设为首页收藏本站
网站公告 | 这是第一条公告
     

 找回密码
 立即注册
缓存时间22 现在时间22 缓存数据 关关难过关关过,夜夜难熬夜夜熬。万般皆苦,悲欢自渡,他人难悟。晚安!

关关难过关关过,夜夜难熬夜夜熬。万般皆苦,悲欢自渡,他人难悟。晚安!

查看: 685|回复: 0

Java中使用 @Builder 注解的简单示例

[复制链接]

  离线 

TA的专栏

  • 打卡等级:即来则安
  • 打卡总天数:23
  • 打卡月天数:0
  • 打卡总奖励:273
  • 最近打卡:2025-11-10 14:13:02
等级头衔

等級:晓枫资讯-上等兵

在线时间
0 小时

积分成就
威望
0
贡献
396
主题
370
精华
0
金钱
1448
积分
812
注册时间
2023-2-10
最后登录
2025-11-10

发表于 2025-8-28 07:52:31 | 显示全部楼层 |阅读模式

大多数同学使用 @Builder 无非就是为了链式编程,然而 @Builder 并不是链式编程的最佳实践,它会额外创建内部类,存在继承关系时还需要使用 @SuperBuilder 注解,设置默认值时也需要额外的 @Builder.Default 去设置默认值,无疑增加了很多不必要的复杂度。

一、案例

@Builder 注解是 Lombok 库中的一个注解,用于简化 Java 对象的构建过程。它通过生成一个构建器模式(Builder Pattern)来创建对象,使得代码更简洁和易于维护。以下是一个使用 @Builder 注解的简单示例:

假设我们有一个 User 类:

  1. import lombok.Builder;
  2. import lombok.ToString;
  3. @Builder
  4. @ToString
  5. public class User {
  6. private String name;
  7. private int age;
  8. private String email;
  9. }
复制代码

在例子中,@Builder 注解会为 User 类生成一个静态内部类 UserBuilder,用于构建 User 对象。@ToString 注解则是为了方便输出对象信息。

使用 @Builder 注解生成的构建器来创建 User 对象:

  1. public class Main {
  2. public static void main(String[] args) {
  3. User user = User.builder()
  4. .name("John Doe")
  5. .age(30)
  6. .email("johndoe@example.com")
  7. .build();
  8. System.out.println(user);
  9. }
  10. }
复制代码

在这个示例中,通过 User.builder() 方法获取一个 UserBuilder 实例,然后通过链式调用设置各个属性,最后调用 build() 方法创建 User 对象。

这种方式的优点是可以灵活地设置对象的属性,并且不需要创建多个构造函数来满足不同的初始化需求。特别是在属性较多的类中,使用 @Builder 可以显著提高代码的可读性和可维护性。

二、不足之处

@Builder 生成的构造器不是完美的,它不能区分哪些参数是必须的,哪些是可选的。如果没有提供必须的参数,构造器可能会创建出不完整或者不合法的对象。

假设我们有一个 Order 类,其中 orderId 是必须的,而 description 是可选的:

  1. import lombok.Builder;
  2. import lombok.ToString;
  3. @Builder
  4. @ToString
  5. public class Order {
  6. private String orderId; // 必须的参数
  7. private String description; // 可选的参数
  8. }
复制代码

在使用 @Builder 构建 Order 对象时,可能会出现这样的情况:

  1. public class Main {
  2. public static void main(String[] args) {
  3. // 忘记设置必须的 orderId
  4. Order order = Order.builder()
  5. .description("This is an optional description")
  6. .build();
  7. System.out.println(order);
  8. }
  9. }
复制代码

在这个示例中,由于 orderId 是一个必须的参数,但在构建 Order 对象时没有提供 orderId,导致生成的对象可能不合法或不完整。

很多人 喜欢 @Builder 和 @Data 搭配使用,导致生成的构造器是可变的,它允许使用 setter 方法修改构造器的状态。这违反了构造器模式的原则,构造器应该是不可变的,一旦创建就不能被修改。

如果非要使用 @Builder ,那么不要用 @Data ,要用 @Getter。相对来说,反而 @Accessors 的行为更符合这个要求。

@Builder 生成的构造器不适合用于短暂的对象,它会增加代码的复杂度和冗余。构造器模式更适合用于生命周期较长、有多种变体的对象。

实际使用中经常发现 @Builder 滥用的情况,有些仅仅一两个属性的类也都要用 @Builder,真的没必要用,直接用全参的构造方法都比这更简洁。

@Builder 生成的构造器不能处理抽象类型的参数,它只能接受具体类型的对象。这限制了构造器的灵活性和扩展性,不能根据不同的需求创建不同风格的对象。

假设我们有一个抽象的 Vehicle 类和一个具体的 Car 类:

  1. public abstract class Vehicle {
  2. private String brand;
  3. public Vehicle(String brand) {
  4. this.brand = brand;
  5. }
  6. public String getBrand() {
  7. return brand;
  8. }
  9. }
  10. public class Car extends Vehicle {
  11. private int numberOfDoors;
  12. public Car(String brand, int numberOfDoors) {
  13. super(brand);
  14. this.numberOfDoors = numberOfDoors;
  15. }
  16. public int getNumberOfDoors() {
  17. return numberOfDoors;
  18. }
  19. }
复制代码

现在,我们尝试使用 @Builder 来创建一个包含 Vehicle 类型参数的 Garage 类:

  1. import lombok.Builder;
  2. import lombok.ToString;
  3. @Builder
  4. @ToString
  5. public class Garage {
  6. private Vehicle vehicle; // 抽象类型参数
  7. }
复制代码

在使用 @Builder 创建 Garage 对象时,我们会遇到问题,因为 Vehicle 是一个抽象类,无法直接实例化:

  1. public class Main {
  2. public static void main(String[] args) {
  3. // 这段代码会有问题,因为 Vehicle 是抽象的,不能直接实例化
  4. Garage garage = Garage.builder()
  5. .vehicle(new Vehicle("Generic Brand") {}) // 错误:不能实例化抽象类
  6. .build();
  7. System.out.println(garage);
  8. }
  9. }
复制代码

解决方案:使用具体类型:在构建器中使用具体类型的对象,而不是抽象类型。例如,直接使用 Car 类

  1. public class Main {
  2. public static void main(String[] args) {
  3. Car car = new Car("Toyota", 4);
  4. Garage garage = Garage.builder()
  5. .vehicle(car)
  6. .build();
  7. System.out.println(garage);
  8. }
  9. }
复制代码

继承关系时,子类需要使用 @SuperBuilder。对象继承后,子类的 Builder 因为构造函数的问题,使用不当大概率会报错,并且无法设置父类的属性,还需要使用 @SuperBuilder 来解决问题。

假设我们有一个父类 Vehicle 和一个子类 Car,并希望通过构建器来设置它们的属性:通过 @SuperBuilder,我们可以在子类的构建器中设置父类的属性:

  1. public class Main {
  2. public static void main(String[] args) {
  3. Car car = Car.builder()
  4. .brand("Toyota") // 设置父类的属性
  5. .model("Corolla") // 设置父类的属性
  6. .numberOfDoors(4) // 设置子类的属性
  7. .build();
  8. System.out.println("Brand: " + car.getBrand());
  9. System.out.println("Model: " + car.getModel());
  10. System.out.println("Number of Doors: " + car.getNumberOfDoors());
  11. }
  12. }
复制代码

@SuperBuilder 注解:它是 @Builder 的增强版本,专门用于处理继承关系。使用 @SuperBuilder 可以在子类的构建器中访问和设置父类的属性。

final 关键字:在这个示例中,属性被声明为 final,确保它们在对象构建后不可变。

构建器链:@SuperBuilder 允许在子类的构建器中调用父类的构建器方法,从而设置父类的属性。

设置默认值需要使用 @Builder.Default。很容易因为对此不了解,导致默认值不符合预期导致出现 BUG。

  1. import lombok.Builder;
  2. import lombok.Getter;
  3. import lombok.ToString;
  4. @Getter
  5. @Builder
  6. @ToString
  7. public class User {
  8. private final String username;
  9. private final String email;
  10. @Builder.Default
  11. private final boolean active = true; // 默认值
  12. @Builder.Default
  13. private final int loginAttempts = 0; // 默认值
  14. }
  15. public class Main {
  16. public static void main(String[] args) {
  17. // 使用构建器创建对象,并未显式设置 active 和 loginAttempts
  18. User user = User.builder()
  19. .username("john_doe")
  20. .email("john.doe@example.com")
  21. .build();
  22. System.out.println(user);
  23. // 显式设置 active 和 loginAttempts
  24. User anotherUser = User.builder()
  25. .username("jane_doe")
  26. .email("jane.doe@example.com")
  27. .active(false)
  28. .loginAttempts(3)
  29. .build();
  30. System.out.println(anotherUser);
  31. }
  32. }
复制代码

到此这篇关于Java中使用 @Builder 注解的简单示例的文章就介绍到这了,更多相关java使用 @Builder 注解内容请搜索晓枫资讯以前的文章或继续浏览下面的相关文章希望大家以后多多支持晓枫资讯!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
晓枫资讯-科技资讯社区-免责声明
免责声明:以上内容为本网站转自其它媒体,相关信息仅为传递更多信息之目的,不代表本网观点,亦不代表本网站赞同其观点或证实其内容的真实性。
      1、注册用户在本社区发表、转载的任何作品仅代表其个人观点,不代表本社区认同其观点。
      2、管理员及版主有权在不事先通知或不经作者准许的情况下删除其在本社区所发表的文章。
      3、本社区的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,举报反馈:点击这里给我发消息进行删除处理。
      4、本社区一切资源不代表本站立场,并不代表本站赞同其观点和对其真实性负责。
      5、以上声明内容的最终解释权归《晓枫资讯-科技资讯社区》所有。
http://bbs.yzwlo.com 晓枫资讯--游戏IT新闻资讯~~~
严禁发布广告,淫秽、色情、赌博、暴力、凶杀、恐怖、间谍及其他违反国家法律法规的内容。!晓枫资讯-社区
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|晓枫资讯--科技资讯社区 本站已运行

CopyRight © 2022-2025 晓枫资讯--科技资讯社区 ( BBS.yzwlo.com ) . All Rights Reserved .

晓枫资讯--科技资讯社区

本站内容由用户自主分享和转载自互联网,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。

如有侵权、违反国家法律政策行为,请联系我们,我们会第一时间及时清除和处理! 举报反馈邮箱:点击这里给我发消息

Powered by Discuz! X3.5

快速回复 返回顶部 返回列表