Lombok
- Quick Start Example for Lombok
- 引入依赖与 IDE 配置
- 核心注解详解
- @Data
- @Getter 和 @Setter
- @ToString
- @EqualsAndHashCode
- @Builder
- @AllArgsConstructor 和 @NoArgsConstructor
- @Value
- @Slf4j / @Log / @Log4j2
- @With
- 原理浅析
Quick Start Example for Lombok
在日常开发中,总会写大量的POJO(如MessageInfo、User、Order),而这些类几乎都要写 getter、setter、toString、equals、hashCode代码量不小,逻辑却千篇一律,纯属体力活。
Lombok 的出现正是为了终结这种冗余。它通过一组简单的注解,在编译期自动生成那些样板方法,让源码只保留核心的字段声明,清晰且高效。
importlombok.Data;@DatapublicclassMessageInfo{privateStringfrom;privateStringto;privateStringmessage;}仅此几行,一个功能完备的 POJO 就完成了。
引入依赖与 IDE 配置
使用 Lombok 前需要先将依赖引入项目,并确保开发环境正确识别。
Maven
<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.30</version><scope>provided</scope></dependency>Gradle
compileOnly'org.projectlombok:lombok:1.18.30'annotationProcessor'org.projectlombok:lombok:1.18.30'小贴士:依赖引入后,务必在 IDE 中安装 Lombok 插件(如 IntelliJ IDEA 的
Lombok插件),并开启Enable annotation processing,否则 IDE 会误报找不到方法。对于 Maven/Gradle 编译,开启注解处理器即可。
核心注解详解
Lombok 提供了一系列注解,组合使用可以应对绝大多数场景。其中最核心、最常用的是@Data。
@Data
@Data是一个组合注解,把它加在类上,相当于同时应用了以下五个注解:
| 注解 | 作用 |
|---|---|
@Getter | 为所有字段生成 getter 方法 |
@Setter | 为所有非 final 字段生成 setter 方法 |
@ToString | 生成包含所有字段的toString()方法 |
@EqualsAndHashCode | 生成基于所有非静态非瞬态字段的equals(Object)和hashCode()方法 |
@RequiredArgsConstructor | 为final字段或有@NonNull约束的字段生成构造器(若没有这类字段,则生成一个公开的无参构造器) |
对于最初的MessageInfo,编译后等价于手写了如下代码:
publicclassMessageInfo{privateStringfrom;privateStringto;privateStringmessage;publicMessageInfo(){}publicStringgetFrom(){returnfrom;}publicvoidsetFrom(Stringfrom){this.from=from;}publicStringgetTo(){returnto;}publicvoidsetTo(Stringto){this.to=to;}publicStringgetMessage(){returnmessage;}publicvoidsetMessage(Stringmessage){this.message=message;}@OverridepublicStringtoString(){...}@Overridepublicbooleanequals(Objecto){...}@OverridepublicinthashCode(){...}}用类图直观展示@Data为MessageInfo自动添加的公开方法:
所有方法均已存在,可直接使用:
MessageInfomsg=newMessageInfo();msg.setFrom("Alice");msg.setTo("Bob");msg.setMessage("Hello Lombok!");System.out.println(msg.getFrom());// AliceSystem.out.println(msg);// MessageInfo(from=Alice, to=Bob, message=Hello Lombok!)可将原来的列表结构拆分为独立的小章节,每个注解一节,内容适当扩写,示例如下(直接替换原### 3.2 其他宝藏注解整节即可):
已将“注解可作用于类或字段”这一重要说明补充到了文章中,主要在@Getter 和 @Setter小节展开,并略微提及了其他注解的类似特性。以下是更新后的3.2 其他宝藏注解完整内容:
@Getter 和 @Setter
可作用在类或字段上,单独控制读写方法的生成。放在类上,会为所有字段生成 getter/setter;放在单个字段上,则只针对该字段生成。还支持通过AccessLevel设置访问级别。
publicclassUser{@Getter@SetterprivateStringname;// 仅为 name 生成@Setter(AccessLevel.PROTECTED)privateStringpassword;// 生成 protected setter}类似地,像@ToString.Exclude和@EqualsAndHashCode.Exclude这样的辅助注解也可以直接标在字段上,用来精准排除某些字段,而不必在类注解里用字符串指定字段名。
@ToString
生成toString()方法。可通过exclude排除敏感字段,或用of指定仅包含某些字段。也可以直接在字段上添加@ToString.Exclude达到相同目的。
@ToString(exclude="password")publicclassUser{privateStringname;@ToString.ExcludeprivateStringpassword;}@EqualsAndHashCode
控制参与相等性比较的字段,同样支持exclude和of,也支持在字段上使用@EqualsAndHashCode.Exclude。在继承关系中,务必设置callSuper = true来调用父类的实现,避免破坏对称性。
@EqualsAndHashCode(callSuper=true)publicclassEmployeeextendsPerson{privateStringempId;}@Builder
为类生成建造者模式,优雅构造复杂对象,尤其适用于多参数且部分可选的场景。
@BuilderpublicclassOrder{privateStringid;privateStringcustomer;privateBigDecimalamount;}// 使用Orderorder=Order.builder().id("1001").customer("Alice").amount(newBigDecimal("99.99")).build();@AllArgsConstructor 和 @NoArgsConstructor
分别生成全参构造器和无参构造器。常与@Data搭配,满足序列化框架(如 Jackson)对无参构造器的需求。
@Data@NoArgsConstructor@AllArgsConstructorpublicclassUser{privateStringname;privateintage;}@Value
不可变数据类的一站式注解,相当于@Data的不可变版本。所有字段默认private final,只会生成 getter,不会生成 setter,同时生成toString、equals和hashCode。适合定义值对象。
@ValuepublicclassAddress{Stringcity;Stringstreet;}@Slf4j / @Log / @Log4j2
直接在类中注入日志对象,省去冗长的声明代码,支持主流日志框架。
@Slf4jpublicclassSomeService{publicvoiddoSomething(){log.info("doing something...");}}@With
为字段生成withXxx方法,返回一个修改了指定字段值的新对象,原对象保持不变,非常适合配合不可变对象使用。
@With@ValuepublicclassPoint{intx,y;}Pointp=newPoint(1,2);Pointp2=p.withX(10);// p2: (10,2),p 不变原理浅析
Lombok 并非运行时动态代理,而是在Java 编译过程中对抽象语法树(AST)动手脚。它的工作流程如下:
具体而言,Lombok 利用了 Java 6 引入的JSR 269 可插拔注解处理 API,直接参与javac的编译过程。在生成 AST 之后、产出字节码之前,Lombok 的处理器会扫描 AST,找到带有自身注解的节点,然后动态插入相应的方法节点。整个过程发生在编译期,对运行时零侵入,也不会带来任何性能损耗。最终生成的.class文件与手写完全一致。