Skip to content

@Builder 是 Lombok 里最常用、也最易踩坑的注解——它一行实现《建造者模式》,但和"无参构造器""继承"配合时有一堆坑。这篇把 @Builder 讲透:基础用法、和构造器的配合、继承场景。

一、@Builder 是什么:一行实现建造者模式

对象字段多、参数可选时,new 一个个塞参数很痛苦。手写建造者模式要一大堆代码,@Builder 一行搞定:

java
@Builder
public class User {
    private String name;
    private int age;
    private String email;
}

// 链式创建:字段多也不乱
User user = User.builder()
        .name("BinMaker")
        .age(18)
        .email("bin@example.com")
        .build();

@Builder 自动生成:builder() 静态方法、build() 方法、每个字段的链式 setter(.name(...).age(...))。对应《建造者模式》的"链式调用",多参可选参对象的构造痛点被一行解决。

二、最大的坑:@Builder 会"吃掉"无参构造器

这是最常踩的坑@Builder 生成的类,默认只有全参构造器builder() 里要能拿到所有字段),没有无参构造器

java
@Builder
public class User {
    private String name;
}

// ❌ 编译/运行报错:没有无参构造器
new User();

// MyBatis/Jackson 反序列化(需要无参构造器)时会报错:
// 无法实例化 User,找不到无参构造器

原因@Builder 的类没有无参构造器,MyBatis 用反射 newInstance() 就炸了。

解决@Builder 必须搭配构造器注解:

java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private String name;
    private int age;
}

三个注解的分工:

  • @Data:getter/setter/toString 等
  • @Builder:建造者模式
  • @NoArgsConstructor:给 MyBatis/Jackson 用(反序列化需要)
  • @AllArgsConstructor:给 @Builder 用(builder 要能构造全字段对象)

口诀@Builder 单独用必踩坑,@Builder + @NoArgsConstructor + @AllArgsConstructor 是标配。

三、继承的坑:@Builder 不支持继承,要用 @SuperBuilder

@Builder 生成的 builder 只包含当前类的字段,不含父类字段

java
public class BaseEntity {
    private Long id;
}

@Data
@Builder
public class User extends BaseEntity {
    private String name;
}

// ❌ 编译报错:builder() 里没有 id 字段(父类字段不在 builder 里)
User.builder().id(1L).name("BinMaker").build();

解决:用 @SuperBuilder(Lombok 1.18.2+):

java
@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class BaseEntity {
    private Long id;
}

@Data
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class User extends BaseEntity {
    private String name;
}

// ✅ builder 包含父类 + 子类所有字段
User.builder().id(1L).name("BinMaker").build();

口诀没有继承用 @Builder,有继承用 @SuperBuilder(父类子类都标)。

四、@Builder 和 final 字段的冲突

@Builder 只能处理非 final 字段,类里有 final 字段会编译报错:

java
@Builder
public class User {
    private final String name;   // final 字段
    private int age;
}
// ❌ 编译报错:@Builder 无法处理 final 字段

原因final 字段必须在构造器里赋值(不能通过 setter/builder 链式赋值)。所以有 final 字段的类别用 @Builder,用构造器或 @RequiredArgsConstructor

五、小结

  • @Builder 一行实现建造者模式,链式创建多字段对象
  • 最大坑:单独用会丢失无参构造器 → 配 @NoArgsConstructor + @AllArgsConstructor
  • 继承坑@Builder 不含父类字段 → 用 @SuperBuilder(父子都标)
  • final 坑@Builder 的类不要有 final 字段

想了解 @Builder 背后的设计思想(为什么链式调用),看《建造者模式》;想了解 Lombok 其他常用注解,看《Lombok 详解:核心注解》。