Lombok 是一个 Java 库,通过注解的方式自动生成 getter/setter、equals、hashCode、toString、构造器等通用代码,显著减少样板代码的编写。
// 不使用 Lombok(70+ 行)
public class User {
private Long id;
private String name;
private String email;
private Integer age;
public User() {}
public User(Long id, String name, String email, Integer age) {
this.id = id;
this.name = name;
this.email = email;
this.age = age;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
// ... 更多 getter/setter
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id) &&
Objects.equals(name, user.name) &&
Objects.equals(email, user.email) &&
Objects.equals(age, user.age);
}
@Override
public int hashCode() {
return Objects.hash(id, name, email, age);
}
@Override
public String toString() {
return "User{" + "id=" + id + ", name='" + name + '\'' +
", email='" + email + '\'' + ", age=" + age + '}';
}
}
// 使用 Lombok(5 行)
@Data
public class User {
private Long id;
private String name;
private String email;
private Integer age;
}生成 getter 和 setter 方法。
@Getter
@Setter
public class User {
private String name;
private Integer age;
}
// 等价于
public class User {
private String name;
private Integer age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; }
}参数:
AccessLevel:控制访问级别(PUBLIC、PROTECTED、PACKAGE、PRIVATE)
@Getter(AccessLevel.PROTECTED)
@Setter(AccessLevel.PRIVATE)
public class User {
private String name;
}
// name 的 getter 为 protected,setter 为 private字段级别使用:
public class User {
@Getter
private String name;
@Getter @Setter
private Integer age;
}综合注解,包含 @Getter、@Setter、@ToString、@EqualsAndHashCode、@RequiredArgsConstructor。
@Data
public class User {
private Long id;
private String name;
private String email;
}
// 自动生成:
// - 所有字段的 getter/setter
// - toString()
// - equals() 和 hashCode()
// - 包含 final 字段的构造器最常用的通用注解,适合 DTO、DO、VO。
构建者模式,支持链式构建对象。
@Builder
public class User {
private Long id;
private String name;
private String email;
private Integer age;
}
// 使用
User user = User.builder()
.id(1L)
.name("张三")
.email("zhangsan@example.com")
.age(25)
.build();优势:
参数多时代码可读性强
类型安全
支持默认值
@Builder(builderMethodName = "customBuilder")
public class User {
@Builder.Default
private Long id = 0L;
private String name;
}
// 自定义构建器方法名
User user = User.customBuilder()
.name("张三")
.build(); // id 默认为 0与 @Data 结合:
@Data
@Builder
public class Company {
private Long companyId;
private String companyName;
private String businessLicenseCode;
}
// 既可以用构建器,也有 getter/setter生成无参和全参构造器。
@NoArgsConstructor
@AllArgsConstructor
public class User {
private String name;
private Integer age;
}
// 等价于
public class User {
public User() {}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
}@RequiredArgsConstructor: 只包含 final 和 @NonNull 字段的构造器
@RequiredArgsConstructor
public class User {
private final String name; // 会被包含在构造器中
private Integer age; // 不会被包含
@NonNull
private String email; // 会被包含在构造器中
}
// 等价于
public class User {
public User(String name, String email) {
this.name = name;
this.email = email;
}
}生成 toString() 方法。
@ToString
public class User {
private String name;
private String email;
private Integer age;
}
// 输出:User(name=张三, email=zhangsan@example.com, age=25)参数:
exclude:排除某些字段
@ToString(exclude = {"password", "email"})
public class User {
private String name;
private String password;
private String email;
}
// 输出:User(name=张三)includeFieldNames:是否包含字段名
@ToString(includeFieldNames = false)
public class User {
private String name;
private Integer age;
}
// 输出:User(张三, 25)生成 equals() 和 hashCode() 方法。
@EqualsAndHashCode
public class User {
private Long id;
private String name;
private String email;
}
// 自动生成 equals() 和 hashCode(),用于集合比较参数:
exclude:排除某些字段(不参与比较)
@EqualsAndHashCode(exclude = {"createTime", "updateTime"})
public class User {
private Long id;
private String name;
private String createTime;
private String updateTime;
}
// 比较时只看 id 和 namecallSuper:是否调用父类的 equals() 和 hashCode()
@EqualsAndHashCode(callSuper = true)
public class User extends BaseEntity {
private String name;
}
// 比较时会调用父类的方法在 setter 或构造器中进行非空检查。
@Setter
public class User {
@NonNull
private String name;
}
// 生成的 setter 会包含非空检查
public void setName(@NonNull String name) {
if (name == null) {
throw new NullPointerException("name is marked @NonNull but is null");
}
this.name = name;
}自定义 getter/setter 的生成方式。
@Getter
@Setter
@Accessors(chain = true)
public class User {
private String name;
private Integer age;
}
// setter 返回 this,支持链式调用
User user = new User()
.setName("张三")
.setAge(25);参数:
fluent = true:去掉 get/set 前缀
@Getter
@Setter
@Accessors(fluent = true)
public class User {
private String name;
}
// 生成 name() 和 name(String) 而不是 getName() 和 setName()
String name = user.name();
user.name("张三");prefix:指定字段前缀
@Getter
@Setter
@Accessors(prefix = "m_")
public class User {
private String m_name;
}
// 生成 getName() 而不是 getM_name()自动注入 SLF4J 日志对象。
@Slf4j
public class UserService {
public void createUser(User user) {
log.info("创建用户: {}", user);
log.debug("详细信息: {}", user.toString());
log.error("发生错误", new Exception());
}
}
// 等价于
public class UserService {
private static final Logger log = LoggerFactory.getLogger(UserService.class);
public void createUser(User user) {
log.info("创建用户: {}", user);
}
}其他日志注解:
@Log:java.util.logging
@Log4j:Apache Log4j
@Log4j2:Apache Log4j 2
@CommonsLog:Apache Commons Logging
@SLF4J:SLF4J with Logback(推荐)
不可变对象(相当于 @Data + @Setter(PRIVATE) + final)。
@Value
public class User {
private String name;
private Integer age;
}
// 等价于
public class User {
private final String name;
private final Integer age;
// 只有 getter,没有 setter
// equals, hashCode, toString 自动生成
}为方法添加同步锁。
@Synchronized
public void updateUser(User user) {
// 方法体
}
// 等价于
private final Object $lock = new Object[0];
public void updateUser(User user) {
synchronized ($lock) {
// 方法体
}
}将检查异常转换为未检查异常。
@SneakyThrows
public void readFile(String path) {
new FileInputStream(path).read();
}
// 等价于
public void readFile(String path) throws IOException {
new FileInputStream(path).read();
}谨慎使用! 可能隐藏异常。
自动关闭资源(类似 try-with-resources)。
@Cleanup
InputStream in = new FileInputStream("file.txt");
// 等价于
InputStream in = new FileInputStream("file.txt");
try {
// 使用 in
} finally {
in.close();
}创建对象的副本并修改某个字段。
@With
@Value
public class Point {
private int x;
private int y;
}
Point p1 = new Point(1, 2);
Point p2 = p1.withX(3); // 创建 (3, 2) 的新对象@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Company {
private Long companyId;
private String companyName;
private String businessLicenseCode;
private CompanyStatus status;
private Boolean deleted;
@ToString.Exclude // 避免 toString 时过多信息
private List<BusinessUser> userList;
@ToString.Exclude
private List<BusinessRole> roleList;
// 业务方法
public void enable() {
this.status = CompanyStatus.ENABLED;
}
public boolean isEnabled() {
return status == CompanyStatus.ENABLED && !deleted;
}
}@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@EqualsAndHashCode // 值对象必须有 equals/hashCode
public class CompanyRegisterInfo {
private String companyName;
private String businessLicenseCode;
private String legalRepresentative;
private String legalIdNumber;
public boolean isComplete() {
return companyName != null && !companyName.isEmpty() &&
businessLicenseCode != null && !businessLicenseCode.isEmpty();
}
}@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class BusinessUser {
private Long userId;
private Long companyId;
private String userName;
private String loginAccount;
@ToString.Exclude // 密码不打印
private String password;
private Boolean isRoot;
private Boolean enabled;
public void enable() {
this.enabled = true;
}
public void disable() {
this.enabled = false;
}
}@Slf4j
public class MerchantDomainService {
private final CompanyRepository companyRepository;
private final BusinessUserRepository businessUserRepository;
@Synchronized
public Company enableCompany(Company company) {
if (!company.getRegisterInfo().isComplete()) {
throw new IllegalStateException("信息不完整");
}
log.info("启用商户: {}", company.getCompanyId());
company.enable();
return companyRepository.save(company);
}
}// DTO/DO(数据传输对象)
@Data
@Builder
public class UserDTO {
private Long id;
private String name;
}
// 值对象(不可变)
@Value
@Builder
public class AddressVO {
private String province;
private String city;
private String district;
}
// 聚合根(可变)
@Data
@Builder
public class UserAggregate {
private Long userId;
private String name;
private AddressVO address;
}@Data
public class User {
private Long id;
private String name;
@ToString.Exclude // 避免序列化大对象
private List<Order> orders;
@ToString.Exclude // 避免打印敏感信息
private String password;
}@Slf4j
@Data
public class UserService {
public void process() {
log.info("处理数据"); // log 直接可用
}
}@Data
@RequiredArgsConstructor
public class Repository {
@NonNull
private final DatabaseConnection connection; // 必须通过构造器传入
private String name; // 可以通过 setter 修改
}@Data
public class User {
private Long id;
private String name;
@ToString.Exclude
@EqualsAndHashCode.Exclude
private Company company; // 避免在 toString/equals 时循环引用
}
@Data
public class Company {
private Long id;
@ToString.Exclude
@EqualsAndHashCode.Exclude
private List<User> users;
}@Data
public class BaseEntity {
private Long id;
private String createTime;
}
@Data
@EqualsAndHashCode(callSuper = true)
public class User extends BaseEntity {
private String name;
}
// equals() 会包含父类的 id 和 createTime// ❌ 错误
@Data
public interface UserService {
}
// ✅ 正确
@Data
public class User {
}Lombok 只能注解在类上,接口默认所有字段都是 public static final。
@Entity
@Data
public class Company {
@Id
private Long id;
@OneToMany
@ToString.Exclude // 避免循环打印
@EqualsAndHashCode.Exclude // 避免循环比较
private List<User> users;
}
@Entity
@Data
public class User {
@Id
private Long id;
@ManyToOne
@ToString.Exclude
@EqualsAndHashCode.Exclude
private Company company;
}@Data
@Builder
public class User {
private String name;
private Integer age;
}
// 既能用 builder
User u1 = User.builder().name("张三").age(25).build();
// 也能用 setter
User u2 = new User();
u2.setName("李四");
u2.setAge(30);
// 还能用 toString/equals
System.out.println(u1);
boolean same = u1.equals(u2);完全兼容,no问题。
解决方案:
安装 Lombok 插件(IntelliJ IDEA 已内置)
启用 IDE 的 Annotation Processing
IntelliJ: Settings → Compiler → Annotation Processors → Enable annotation processing
重新启动 IDE
@Getter
public class User {
private String name;
// 自定义 getter
public String getName() {
return name == null ? "Unknown" : name.toUpperCase();
}
}
// Lombok 不会再生成 getter,使用你自定义的版本@Builder
public class Config {
@Builder.Default
private int timeout = 30;
@Builder.Default
private String host = "localhost";
private int port; // 必须指定
}
// 使用
Config cfg = Config.builder()
.port(8080)
.build();
// timeout = 30, host = "localhost", port = 8080Lombok 注解只在编译时生成代码,运行时零开销。
// 编译后的字节码
public class User {
private String name;
public String getName() { // 编译时生成
return this.name;
}
}生成的 equals() 方法会比手写版本多占用内存
对于大规模对象集合,可考虑 exclude 减少字段比较
@EqualsAndHashCode(exclude = "largeList")
public class Document {
private String content;
private List<byte[]> largeList; // 不参与比较
}// 简单数据对象
@Data
public class SimpleDTO { }
// 复杂对象需要灵活构建
@Data
@Builder
public class ComplexEntity { }
// 不可变值对象
@Value
public class ValueObject { }
// 有日志需求的服务
@Slf4j
@Service
public class MyService { }Maven 依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>