1. 概述
在日常开发中,实体类(POJO)几乎都会配备 get
和 set
方法。虽然这是标准做法,但有时我们希望代码更简洁、更具表达力。
本文将深入介绍 Lombok 的 @Accessors
注解,它支持 流式调用(fluent)、链式调用(chained)、前缀剔除(prefix) 以及 方法设为 final(makeFinal) 等高级特性,让你的代码更优雅。
⚠️ 使用前请确保你的 IDE 已安装 Lombok 插件,否则编译会报错。
2. 标准访问器
在进入 @Accessors
之前,先回顾下 Lombok 默认的 @Getter
和 @Setter
行为。
定义一个普通实体类:
@Getter
@Setter
public class StandardAccount {
private String name;
private BigDecimal balance;
}
测试其 getter/setter 是否正常工作:
@Test
public void whenStandardAccount_thenHaveStandardAccessors() {
StandardAccount account = new StandardAccount();
account.setName("Standard Accessors");
account.setBalance(BigDecimal.TEN);
assertEquals("Standard Accessors", account.getName());
assertEquals(BigDecimal.TEN, account.balance());
}
✅ 这是“教科书式”的写法,但略显啰嗦。接下来我们看看如何用 @Accessors
改造它。
3. 流式访问器(Fluent Accessors)
使用 @Accessors(fluent = true)
可以生成无 get/set
前缀的方法。
⚠️ 注意:
chain = true
是默认行为,这里我们先显式关闭以聚焦fluent
特性。
@Accessors(fluent = true, chain = false)
@Getter
@Setter
public class FluentAccount {
private String name;
private BigDecimal balance;
}
测试代码变得更简洁:
@Test
public void whenFluentAccount_thenHaveFluentAccessors() {
FluentAccount account = new FluentAccount();
account.name("Fluent Account"); // 替代 setName()
account.balance(BigDecimal.TEN); // 替代 setBalance()
assertEquals("Fluent Account", account.name()); // 替代 getName()
assertEquals(BigDecimal.TEN, account.balance()); // 替代 getBalance()
}
✅ 方法名直接使用字段名,读起来像“配置项”,非常自然。
4. 链式访问器(Chained Accessors)
@Accessors(chain = true)
让 setter 返回 this
,从而支持链式调用。
我们结合 fluent
一起使用:
@Accessors(fluent = true, chain = true)
@Getter
@Setter
public class ChainedFluentAccount {
private String name;
private BigDecimal balance;
}
✅ 实际上只写
@Accessors(fluent = true)
就够了,因为chain
默认为true
。
测试代码可以直接“串”起来:
@Test
public void whenChainedFluentAccount_thenHaveChainedFluentAccessors() {
ChainedFluentAccount account = new ChainedFluentAccount()
.name("Fluent Account")
.balance(BigDecimal.TEN);
assertEquals("Fluent Account", account.name());
assertEquals(BigDecimal.TEN, account.balance());
}
✅ 这种写法极大减少了样板代码,类似 Builder 模式的效果,简单粗暴。
💡 提示:Lombok 的
@Builder
就是基于这种链式 fluent 风格实现的。
5. 前缀剔除(Prefix Accessors)
有些老项目字段名带前缀(匈牙利命名法),比如 sName
、bdBalance
。直接生成 getter 会变成 getSName()
,非常别扭。
@Accessors(prefix = {...})
可以指定要忽略的字段前缀:
@Accessors(prefix = {"s", "bd"})
@Getter
@Setter
public class PrefixedAccount {
private String sName;
private BigDecimal bdBalance;
}
测试验证前缀已被剔除:
@Test
public void whenPrefixedAccount_thenRemovePrefixFromAccessors() {
PrefixedAccount account = new PrefixedAccount();
account.setName("Prefixed Fields");
account.setBalance(BigDecimal.TEN);
assertEquals("Prefixed Fields", account.getName());
assertEquals(BigDecimal.TEN, account.getBalance());
}
✅ 生成的方法是 getName()
而不是 getSName()
,清爽多了。
前缀匹配规则
Lombok 的前缀匹配有两条关键规则,避免误伤:
前缀后必须紧跟大写字母
例如字段state
以s
开头,但t
是小写,所以不会被当作s
前缀处理,不会生成getTate()
这种离谱方法。前缀本身以非字母结尾时也匹配
比如字段s_notes
,前缀设为"s_"
:@Accessors(prefix = "s_") private String s_notes;
即使
_n
中的n
是小写,但由于前缀s_
以_
(非字母)结尾,仍会正确生成setNotes()
和getNotes()
。
6. Final 访问器(Final Accessors)
从 Lombok v1.18.24 开始,支持 makeFinal = true
,生成的 getter/setter 会被标记为 final
,防止子类重写。
适用于那些不允许被覆盖的访问器:
@Accessors(makeFinal = true)
@Getter
@Setter
public class FinalAccount {
private String name;
private BigDecimal balance;
}
测试验证功能正常且方法为 final:
@Test
public void whenFinalAccount_thenHaveFinalAccessors() {
FinalAccount account = new FinalAccount();
account.setName("Final Account");
account.setBalance(BigDecimal.TEN);
assertEquals("Final Account", account.getName());
assertEquals(BigDecimal.TEN, account.getBalance());
// 使用反射验证所有 getter/setter 是否为 final
boolean getterSettersAreFinal = Arrays.stream(FinalAccount.class.getMethods())
.filter(method -> method.getName().matches("^(get|set)(Name|Balance)$"))
.allMatch(method -> Modifier.isFinal(method.getModifiers()));
assertTrue(getterSettersAreFinal);
}
✅ 安全性提升,尤其在继承体系中防止意外覆盖。
组合使用示例
makeFinal
可与其他选项叠加:
@Accessors(makeFinal = true, fluent = true, chain = true)
@Getter
@Setter
public class FinalChainedFluentAccount {
private String name;
private BigDecimal balance;
}
测试链式调用并验证方法为 final:
@Test
public void whenFinalChainedFluentAccount_thenHaveFinalAccessors() {
FinalChainedFluentAccount account = new FinalChainedFluentAccount()
.name("Final Chained Fluent Account")
.balance(BigDecimal.TEN);
assertEquals("Final Chained Fluent Account", account.name());
assertEquals(BigDecimal.TEN, account.balance());
// 验证 fluent 方法 name() 和 balance() 是否为 final
boolean getterSettersAreFinal = Arrays.stream(FinalChainedFluentAccount.class.getMethods())
.filter(method -> method.getName().matches("^(name|balance)$"))
.allMatch(method -> Modifier.isFinal(method.getModifiers()));
assertTrue(getterSettersAreFinal);
}
✅ 一行代码搞定对象初始化,同时保证方法不可重写,踩坑少。
7. 全局配置(Configuration Properties)
如果项目中大量使用某种风格(比如全用 fluent + chain),可以通过 lombok.config
文件统一配置:
lombok.accessors.chain = true
lombok.accessors.fluent = true
该配置对所在目录及其子目录生效。推荐放在项目根目录或 src/main/java
下。
✅ 从此无需在每个类上重复加注解,团队风格统一,省心省力。
更多配置项参考:Lombok 官方配置指南
8. 总结
@Accessors
是 Lombok 中一个低调但极其实用的注解,通过几个布尔选项就能显著提升代码可读性和简洁度。
关键特性回顾:
特性 | 作用 | 推荐场景 |
---|---|---|
fluent = true |
去掉 get/set 前缀 | 配置类、DSL 风格 API |
chain = true |
setter 返回 this | 链式初始化 |
prefix = {...} |
忽略字段前缀 | 老系统兼容、匈牙利命名 |
makeFinal = true |
方法标记为 final | 防止子类重写,增强封装 |
✅ 建议在新项目中大胆使用 fluent + chain
组合,写出来的代码干净利落。
源码地址:https://github.com/yourname/tutorials/tree/master/lombok-modules/lombok-2