资讯动态

Java开发必备Lombok实战:用注解消除样板代码

发布时间:2026/10/1 1:10:38 来源:尧图企业网站定制
1. Lombok 到底解决了什么问题为什么 Java 开发者离不开它先讲一个很现实的场景你写一个实体类要加几个字段然后就得配套生成 getter、setter、构造器、toString、equals、hashCode。以前用 IDE 的快捷键生成看着是省事可是后续每改一个字段就要重新生成一遍代码里动不动就是几百行的样板代码。真正有业务逻辑的部分反而被淹没在一堆重复代码里。我见过不少项目实体类里的 getter/setter 比业务代码还长读起来极其痛苦。Lombok 这个工具的核心思路就一句话用注解替代手写样板代码让代码在编译期自动生成。你只需要在类上标注Data编译后生成的.class文件里就会自动带上 getter、setter、toString、equals、hashCode 这些方法。源码里干干净净IDE 里也能正常调用那些方法因为 Lombok 的插件会告诉 IDE“这些方法编译期会生成”所以自动补全、跳转这些功能都不受影响。我第一次接触 Lombok 时的反应是“这玩意儿靠谱吗会不会运行时出问题”后来在几个生产项目里用了两年多它可以做到编译期生成代码不依赖运行时反射对性能没有影响这一点比很多“运行时动态生成”的方案要稳得多。它的原理也不复杂利用 JDK 1.6 以后提供的注解处理器Annotation Processor机制在javac编译源码时拦截 AST抽象语法树往里面添加新的方法节点再参与后续的编译过程。说到底就是在编译阶段帮你“无中生有”地补全代码。现在 Lombok 在 Java 生态里的地位基本属于“用了就回不去”的工具。无论是老牌的 Spring MVC 项目还是 Spring Boot、Spring Cloud 微服务架构实体类、DTO、VO 这些对象里几乎都能看到Data、Builder、Slf4j的身影。它能把 Java 代码的“啰嗦”程度降下来一截让开发者把精力放到真正需要思考的业务逻辑上。2. 从接入到上手Lombok 的安装与项目配置2.1 引入依赖Maven 和 Gradle 的标准写法Lombok 的使用方式非常简单它不是运行时框架所以依赖范围一般设置为provided或者compileOnly意思是编译时需要打包进最终产物时可不要。Maven 项目里在pom.xml的dependencies节点中加入dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.30/version scopeprovided/scope /dependencyGradle 项目则在build.gradle里写dependencies { compileOnly org.projectlombok:lombok:1.18.30 annotationProcessor org.projectlombok:lombok:1.18.30 }注意 Gradle 配置里的annotationProcessor这行它是专门给注解处理器用的。如果你漏了这行现代版本的 Gradle 在编译时很可能提示“程序包lombok不存在”或者“找不到符号”因为注解处理器没有被正确触发。这是新手最容易踩的坑之一。Maven 的编译器插件有时也需要显式指定注解处理器路径尤其是当你同时使用了 MapStruct、QueryDSL 这类其他注解处理器时。常见做法是在maven-compiler-plugin里加上plugin groupIdorg.apache.maven.plugins/groupId artifactIdmaven-compiler-plugin/artifactId configuration annotationProcessorPaths path groupIdorg.projectlombok/groupId artifactIdlombok/artifactId version1.18.30/version /path /annotationProcessorPaths /configuration /plugin这样能避免编译时注解处理器缺失带来的诡异问题。2.2 IDEA 中的配置与手动安装插件大多数情况下在 IDEA 里使用 Lombok 只需要做两件事安装 Lombok 插件确保开启了注解处理。新版 IDEA2020.1 之后已经内置了 Lombok 插件老版本需要手动安装。打开File - Settings - Plugins搜索 Lombok点击 Install 即可。然后进入Settings - Build, Execution, Deployment - Compiler - Annotation Processors勾选Enable annotation processing这个开关如果没开Lombok 的注解处理器不会被编译期调用结果就是源码看着没问题编译却报“找不到符号 getXxx()”。有同学遇到 IDEA 提示 “java: You arent using a compiler supported by lombok, so lombok will not work”这个问题通常出现在 IDEA 自带的编译器版本比较旧或者项目里强制指定了某些老版本的 javac或者是使用的是 Eclipse 编译器ECJ而不是 javac。解决办法是检查项目 SDK 版本尽量用 JDK 8 以上同时确认maven-compiler-plugin的source和target版本不要低于 1.8。如果还在用 Eclipse 编译器需要考虑切回 javac或者参考 Lombok 官方文档里对 ECJ 的支持说明。2.3 验证安装是否成功配置完成后最快验证方式就是写一个最简单的实体类import lombok.Data; Data public class User { private String name; private Integer age; }然后在其他代码里直接写User user new User(); user.setName(张三); user.setAge(18); System.out.println(user.toString());如果编译通过、运行正常说明 Lombok 已经生效了。如果你在源码里看不到setName方法但 IDEA 不报错也说明插件和编译期生成都工作正常如果 IDEA 报红多半是插件没装好或者注解处理没开启。3. 常用注解逐个拆解不只是 Data 那么简单Lombok 最常用的注解是Data但如果你只知道Data那说明还没有完全发挥出这个工具的威力。下面我按使用频率和场景一个个讲每个注解都配实际例子和适用场景。3.1 Getter 和 Setter这两个注解可以加在类上也可以加在字段上。加在类上表示给所有非 static 字段生成 getter 和 setter加在字段上比如public class Order { Getter private String orderNo; Setter private BigDecimal amount; }这就只给orderNo生成 getter给amount生成 setter。有些字段需要只读或者只写的时候很实用比如创建时间放在构造函数里初始化之后不该被修改就可以只加Getter。还支持指定访问级别Getter(AccessLevel.PROTECTED) private Integer status;这样 getter 是 protected 的外部包不能随意访问内部逻辑却能正常使用。3.2 ToString自动生成toString()方法。默认会打印所有字段名和值不过有两个常见问题需要注意字段里有敏感信息比如密码、token不希望出现在日志里可以用exclude排除ToString(exclude {password, salt})类之间有继承关系默认父类的字段不会打印实际上所有字段都不打印需要callSuper trueToString(callSuper true)3.3 EqualsAndHashCode自动生成equals和hashCode。这个注解有个细节很容易踩坑默认只比较当前类定义的字段不考虑父类。如果父类也有业务字段比如抽象基类里的id那就需要设置callSuper trueEqualsAndHashCode(callSuper true) public class Product extends BaseEntity { private String name; }如果不加两个对象即使id不同只要name相同equals 结果就是 true这在做对象比较、去重、放入 Set 时会产生难以排查的 bug。3.4 NoArgsConstructor / RequiredArgsConstructor / AllArgsConstructor三个构造器注解对应三种不同需求NoArgsConstructor生成无参构造方法。和 JPA、MyBatis 这类框架配合时特别重要因为框架需要通过无参构造创建对象再反射赋值。AllArgsConstructor生成包含所有字段的构造方法所有字段按声明顺序作为参数。RequiredArgsConstructor只为final字段以及标注了NonNull的字段生成构造方法。这个注解在 Spring 构造器注入时非常常用。3.5 Data 和 ValueData是上述常用注解的组合Getter Setter ToString EqualsAndHashCode RequiredArgsConstructor。一个注解搞定一个标准 POJO。Value则是不可变类的组合所有字段默认为private final只有 getter没有 setter类本身还会被标记为final。适合做值对象、枚举、配置属性类。两者的选择逻辑很简单需要可变对象用Data希望对象创建后不可变用Value。3.6 Builder 与 Builder.DefaultBuilder可以说是 Lombok 最实用的注解之一它为你生成一个建造者模式的内部类让你可以链式赋值User user User.builder() .name(李四) .age(20) .build();这种写法在字段多、可选项多的场景下比长长的构造器参数列表清晰得多也比连续 set 更优雅。有一点需要特别注意被Builder修饰的类如果某个字段没有显式赋值它会被设为 Java 默认值null、0、false而不是你在字段声明处写的初始值。比如Data Builder public class Config { private Integer pageSize 20; }链式调用时如果没有.pageSize(20)得到的pageSize是 null不是 20。解决办法是加Builder.DefaultData Builder public class Config { Builder.Default private Integer pageSize 20; }这是 Lombok 里出镜率极高的坑一定要记牢。3.7 Slf4j 等日志注解Slf4j会自动生成一个名为log的静态 Logger 字段Slf4j Service public class UserService { public void doSomething() { log.info(handle something); } }不用手写private static final Logger log LoggerFactory.getLogger(...)也不用担心类改名之后 logger 名字没有同步更新。除了Slf4j还有Logjava.util.logging、Log4j2、CommonsLog等根据项目用的日志框架选择。3.8 NonNullNonNull可以加在字段上也可以加在方法参数上。加在字段上生成的 setter 和构造器会带上 null 检查传入 null 时直接抛出NullPointerException。加在方法参数上则会在方法开头自动插入判空逻辑。这相当于把常见的“防御式编程”代码从手写变成了注释式声明代码简洁不少。4. 进阶用法与常见问题排查实录4.1 Lombok 与 Spring 依赖注入的绝佳组合用RequiredArgsConstructor做构造函数注入是我这几年最推荐的写法。比如Service RequiredArgsConstructor public class UserServiceImpl implements UserService { private final UserMapper userMapper; private final RedisTemplateString, String redisTemplate; Override public User getUserById(Long id) { return userMapper.selectById(id); } }因为字段是final的RequiredArgsConstructor会生成一个包含这两个字段的构造函数Spring 会直接通过构造函数完成注入。相比Autowired字段注入构造函数注入的优点非常明确依赖关系显式化、方便写单元测试、类加载后所有依赖必然就绪不会出现字段注入为 null 的情况。不过有个前提作为依赖的 Bean 必须已经存在于 Spring 容器中如果是循环依赖构造函数注入是会直接启动报错的这一点和Autowired字段注入的表现不一样。所以用构造函数注入时要留意有没有 A 依赖 B、B 又依赖 A 的情况。4.2 Builder 和 Data 同时用序列化要注意什么这个组合在 DTO、VO 类里经常出现Data Builder public class OrderVO { private String orderNo; private BigDecimal amount; }它能让你既方便链式构造对象又保留了 getter、setter 和 toString。但有两个注意点第一Builder生成的构造方法是包级私有的如果不加NoArgsConstructor和AllArgsConstructor某些 JSON 反序列化框架比如 Jackson 的老版本在反序列化时找不到合适的构造器就报错。常见做法是Data Builder NoArgsConstructor AllArgsConstructor public class OrderVO { // fields }这样Builder负责构建Jackson 反序列化时使用无参构造setter或者用全参构造怎么都不会冲突。第二NoArgsConstructor会和Builder冲突吗不会Lombok 从 1.16 开始就支持这个组合。但在很老的 Lombok 版本上确实有兼容问题如果项目里还在用 1.16 以前的版本建议优先升级到最新稳定版。4.3 Lombok 与 Lombok 的“DDD”之争要不要用这个问题在团队里经常被拿出来讨论。反对的一方主要担心三点成员需要学习注解入门成本增加。如果某个成员用了 IDE 的“Delombok”功能把注解直接展开成了源码代码库会一下子多出大量重复代码。代码的“真实感”降低了新人看到源码里只有字段没有方法会困惑方法在哪。我个人的观点很明确在这个问题上团队规范比工具本身更值得关注。Lombok 的收益是实打实的代码量减少带来的可读性提升、修改字段时不用再手工重写一系列方法、日志注解省去静态 Logger 声明这些都是日常高频收益。至于“不懂注解”的问题一次团队内训 30 分钟就能解决没必要因噎废食。真正需要留意的是代码审查环节明确约定哪些类可以用 Lombok、哪些场景不要硬套避免整个项目风格分裂。4.4 Lombok 警告You arent using a compiler supported by lombok这个报错的完整信息大概是java: You arent using a compiler supported by lombok, so lombok will not work. Your platform: jdk.internal.vm.compiler.collections ...触发条件通常是 IDE 内置编译器不是标准 javac或者项目里显式设置了 Eclipse 编译器。排查顺序我给你整理好了检查Settings - Build, Execution, Deployment - Compiler - Java Compiler确保用的是 Javac而不是 Eclipse。检查 pom.xml 或 build.gradle 里有没有强制指定编译器的插件配置。检查 JDK 版本极老版本的 JDK 和最新版 Lombok 也可能不兼容。Lombok 1.18.30 支持 JDK 8 到 JDK 21如果你的 JDK 版本超过了 21建议升级 Lombok 到最新版。如果用的 Maven 编译器插件版本过旧也容易出现类似异常把maven-compiler-plugin升到 3.11.0 以上。另外还有一类奇怪场景同一个模块里 Lombok 和某个字节码增强插件同时存在比如 AspectJ 的编译期织入。这类场景下 Lombok 有时会失效因为 AspectJ 编译器对 AST 的处理和 javac 不一样。遇到这种情况优先考虑把字节码增强从编译期织入改成加载期织入LTW或者延后到 Lombok 处理完之后再增强。4.5 热部署场景下 Lombok 方法消失在 Spring Boot DevTools 或者 JRebel 这类热部署工具的环境里偶尔会遇到改动代码后 IDE 提示找不到setXxx方法。这通常不是 Lombok 的问题而是热部署机制对增量编译支持得不完整导致 IDE 的索引没有刷新。解决方式很简单触发一次全量编译/重新构建项目或者重启应用。如果频繁出现可以考虑关闭热部署改用较新版本 IDEA 自带的 HotSwap 功能——它对编译后类结构变化的支持比旧方案好很多。4.6 Lombok 生成的代码能和手写代码共存吗可以。如果你在某一个类上用了Data又手写了一个toString()Lombok 不会覆盖你手写的方法它检测到已有方法定义时会跳过对应方法的生成。同理手写了某个字段的 getterLombok 就不会重复生成。这个机制很贴心让你可以针对个别字段做定制逻辑既享受自动化带来的省力也有局部手工定制的空间。4.7 遇到 debug 时看不到局部变量是 Lombok 的锅吗不是。Lombok 只在编译期修改 AST生成最终字节码它并不会影响调试信息的生成。如果你在 IDEA 里断点调试时看不到局部变量一般是因为编译时 debug 信息没开或者 IDE 的调试器配置问题。可以在 javac 参数里加上-gIDEA 默认会开启如果你用了自定义 Maven 配置检查有没有覆盖掉。5. 再聊几个冷门但特别有用的 Lombok 玩法5.1 With生成“修改副本”的方法JDK 14 引入了 record让不可变对象写起来舒服了很多。但如果你还在用传统 Java又要写不可变对象风格With就很有用了Getter With public class User { private final String name; private final Integer age; }它会为每个字段生成一个withXxx方法返回一个副本对象只修改指定字段。典型用法User youngUser new User(王五, 22); User olderUser youngUser.withAge(23);原对象youngUser不变olderUser是年龄改过的新对象。这种模式在做事件溯源、数据快照时非常顺手。5.2 SneakyThrows免检异常也能“偷偷”抛出Java 里 checked exception 必须显式捕获或声明这经常让代码变得啰嗦。SneakyThrows可以加在方法上让方法里的 checked exception 不必在签名里声明也不需要 try-catchSneakyThrows public String readContent(Path path) { return new String(Files.readAllBytes(path), StandardCharsets.UTF_8); }这个注解的争议比较大因为它在字节码层面偷换了异常处理逻辑把 checked exception 直接包装后抛出去。我不是特别建议在对外 API 层用它因为调用的人并不知道你会抛出哪个异常容易导致异常处理不完整。但在内部工具方法、测试代码里它确实能省去大段 try-catch。用的时候想清楚不是所有地方都适合。5.3 Accessors链式 set 的另一种姿势加了Accessors(chain true)之后setter 方法会返回this可以这样写User user new User().setName(赵六).setAge(25);如果同时用了Data和Accessors(chain true)你可能会发现 MyBatis、Jackson 在反序列化时有问题因为标准 JavaBean 规范要求 setter 返回 void而这里返回了User。Spring 的 BeanUtils、MyBatis 的自动映射对这种情况的处理配合度各不相同。我的建议是只在局部明确使用链式 set 的类上使用别全局打开。5.4 在记录类Record上的用法Java 16 正式发布 record 之后很多人觉得 record 可以替代 Lombok。确实record 天然自带构造器、getter、equals、hashCode、toString对应了 Lombok 相当大一部分能力。但 Lombok 在几个点仍然有优势record 的字段是 final 的想变成可变对象还得重新声明类。record 没有无参构造器和某些持久层框架配合麻烦。record 没有 Builder 模式需要自己写静态工厂方法或额外引入 Builder。所以现在的趋势不是“二选一”而是“按需组合”。实体类、DTO 继续用 Lombok一些纯数据传输且不需要被框架特殊处理的场景直接用 record 更干净。5.5 自定义 Lombok 注解以 Slf4j 为例看一下它的设计思路自己写一个自定义注解处理器并不复杂Lombok 的扩展机制允许你基于它的 API 实现自定义注解不过绝大多数项目用不到这个能力。这里提一下 Slf4j 的设计细节它本质上是替你在源码 AST 里增加一个静态字段声明private static final org.slf4j.Logger log org.slf4j.LoggerFactory.getLogger(YourClassName.class);Lombok 在生成时自动拿到当前类名并填入所以你不用手写。如果你希望日志对象名不叫log而叫logger可以通过Slf4j注解的topic属性和 Lombok 配置lombok.log.fieldName调整。6. 项目里 Lombok 实践的一些建议与避坑清单最后把我这几年在项目中使用 Lombok 的经验整理成一份可以直接抄作业的清单。6.1 团队规范建议实体类/POJO/DTO/VO统一使用Data有建造需求的加Builder同时配合NoArgsConstructor和AllArgsConstructor避免和序列化框架产生冲突。Service 层统一使用RequiredArgsConstructorfinal字段做构造器注入。日志统一使用Slf4j不要在 Logger 命名上花心思。配置类ConfigurationProperties用Data或ConfigurationProperties(prefix xxx)搭配 getter/setter。枚举/常量类、工具类不要用Data。6.2 常见坑速查表场景症状解决办法编译报“找不到符号 getXxx/setXxx”注解处理器没生效检查 IDEA 的 Annotation Processing 开关检查 Maven/Gradle 的 annotationProcessor 配置输出报告“You arent using a compiler supported by lombok”使用了非 javac 编译器切换回 Javac升级编译器插件和 Lombok 版本Builder 下字段初始值丢失字段值变成 null/0/false给字段加 Builder.Default序列化失败JSON 反序列化说没有合适的构造器加上 NoArgsConstructor 和 AllArgsConstructorequals 比较结果和预期不符两个对象 id 不同却 equals true在 EqualsAndHashCode 里加 callSuper true类继承时 toString 缺少父类字段日志里看不到父类字段在 ToString 里加 callSuper trueLombok 和 MapStruct 一起编译报错注解处理器冲突在 maven-compiler-plugin 里显式配置 annotationProcessorPaths6.3 版本选择Lombok 的版本迭代不算太快但不同版本对 JDK 的支持差异很大。当前主流稳定大版本是 1.18.x如果你的项目用的是 JDK 8 到 JDK 17选最新的 1.18.30 或更高版本就好。如果升级到了 JDK 21 甚至更高先确认 Lombok 最新版是否已支持Lombok 官方对 JDK 新版本的适配一般有滞后遇到 JDK 21 编译异常时最直接的办法就是升 Lombok 版本、同时看看是不是 JDK 补丁版本不兼容。6.4 不要过度使用 Lombok前几年见过一个项目连常量类上都标了Data那个类没有任何实例状态生成一堆无意义的方法纯属噪音。Lombok 的定位是“减少样板代码”不是“消灭所有手写代码”。当一个类只有一两个字段手写 getter/setter 其实也就几行用 Lombok 反而多一个编译依赖。工具是为人服务的拿着锤子看什么都是钉子这心态在工程上要不得。我个人目前的使用习惯可以总结为实体对象、DTO 无脑Data BuilderService 里无脑Slf4j需要参数校验的对象用RequiredArgsConstructor配合final字段写死依赖。这样的组合我用了两三年项目里几乎没有因为 Lombok 本身出过问题真正出问题的全是环境配置和版本兼容也就是上面列表里那些点。只要把编译期环境理顺了它的稳定性是相当放心的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑