@Builder适用于构建即冻结的不可变对象,生成独立Builder类并需搭配@NoArgsConstructor;@Accessors(chain=true)适用于实例化后可变链式赋值,仅修改setter返回值为this,更轻量但不兼容部分反射工具。

@Builder 和 @Accessors 都能实现流式调用,但适用场景和底层机制完全不同:@Builder 是构造阶段的不可变构建,@Accessors(chain = true) 是实例化后的可变链式赋值。混用不光冗余,还容易踩坑。
@Builder 适合「创建即确定状态」的实体
比如 DTO 构建、API 请求参数封装、领域对象初始化等——这些对象一旦 build 出来就不该再被随意修改。
-
@Builder生成的是独立的XXXBuilder内部类,调用build()后返回新实例,原始 builder 不影响结果 - 必须搭配
@NoArgsConstructor(框架反射需要)和@AllArgsConstructor(避免与@Data的@RequiredArgsConstructor冲突) - 父类字段默认不参与构建,要用
@SuperBuilder替代,否则子类builder()调用会漏掉父类属性 - 示例:
@Data @NoArgsConstructor @AllArgsConstructor @SuperBuilder public class User { private Long id; private String name; private String email; }调用:User.builder().name("Alice").email("a@b.com").build()
@Accessors(chain = true) 适合「先 new 再赋值」的轻量场景
比如测试数据组装、临时对象填充、Web 层快速包装响应体——不需要 builder 类开销,也不追求构建时的不可变语义。
对设计或页面进行 WCAG 2.1 AA 无障碍审计。触发关键词:“audit accessibility”、 “check a11y”、 “is this accessible?” 或在审查设计时使用。
-
@Accessors(chain = true)只改 setter 返回值为this,不新增任何类或方法,编译后就是普通 set 调用 - 不能和
@Builder同时加在同一个类上,否则setXxx()和xxx()方法签名冲突(Lombok 会报错) - 注意:Spring 的
BeanUtils.copyProperties默认跳过非void返回值的 setter,所以必须用org.springframework.beans.BeanUtils,别误导入 Apache 的版本 - 示例:
@Data @Accessors(chain = true) public class Result<T> { private Integer code; private String msg; private T data; }调用:new Result().code(200).msg("ok").data("hello")
常见错误:@Builder + @Data + 没加无参构造器
这是最典型的运行时崩溃点:MyBatis、Jackson、Spring MVC 在反序列化或注入时依赖无参构造器,而 @Builder 会触发 Lombok 自动生成全参构造器,把默认无参构造器挤没了。
- 现象:
java.lang.InstantiationException或Cannot construct instance of XXX - 修复方式:显式加
@NoArgsConstructor,哪怕类里没 final 字段也要加 - 如果用了
@Data,它自带@RequiredArgsConstructor,和@Builder生成的全参构造器重叠,可能引发编译警告甚至构造器歧义,所以建议统一用@AllArgsConstructor显式控制 - 别依赖 IDE 自动生成构造器——Lombok 注解是编译期行为,IDE 的提示可能滞后或不准
选哪个?看对象生命周期是否允许中途修改
如果业务逻辑要求「构建完成即冻结」(比如命令对象、审计日志实体),用 @SuperBuilder;如果只是临时拼个返回值、测试造数、或者要复用已有实例做浅拷贝,@Accessors(chain = true) 更轻、更直接。两者不是替代关系,而是分工关系——前者管「怎么生出来」,后者管「生出来后怎么快速配好」。
最容易被忽略的一点:@Accessors 的 fluent 模式(如 id(123) 替代 setId(123))虽简洁,但会破坏 JavaBean 规范,导致多数反射工具(包括部分 JSON 库)无法识别属性,除非你明确知道所有上下游组件都支持它,否则慎用。

















