Lombok 全面详解
Lombok 是一个 Java 库,通过注解自动生成代码,减少样板代码,提高开发效率。
核心功能概览
1. 简化 Getter/Setter
// 传统写法
public class User {
private String name;
private int age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
// Lombok 写法
@Data
public class User {
private String name;
private int age;
}
2. 构造函数生成
// 全参构造函数
@AllArgsConstructor
public class Point {
private int x, y;
}
// 无参构造函数
@NoArgsConstructor
public class Config {
private String value;
}
// 必要参数构造函数
@RequiredArgsConstructor
public class Service {
private final UserRepository repository;
@NonNull
private String serviceName;
}
3. Builder 模式
@Builder
public class Product {
private Long id;
private String name;
private BigDecimal price;
// 使用
// Product product = Product.builder()
// .id(1L)
// .name("Laptop")
// .price(new BigDecimal("999.99"))
// .build();
}
核心注解详解
1. @Data - 全能注解
@Data // 等价于:@Getter @Setter @ToString @EqualsAndHashCode @RequiredArgsConstructor
public class User {
private Long id;
private String username;
private String email;
private final LocalDateTime createdAt = LocalDateTime.now();
}
2. @Value - 不可变对象
@Value // 所有字段都是 private final,只生成 getter
@Builder
public class ImmutablePoint {
int x;
int y;
String color;
// 生成的类相当于:
// public final class ImmutablePoint {
// private final int x;
// private final int y;
// ...
// }
}
3. @Builder - 建造者模式
@Builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Order {
private Long id;
private String orderNo;
private BigDecimal amount;
@Builder.Default
private OrderStatus status = OrderStatus.PENDING;
@Singular
private List<String> items;
// 支持集合操作
// Order.builder()
// .item("Book")
// .item("Pen")
// .build();
}
4. @Slf4j - 日志
@Slf4j
@Service
public class UserService {
public void createUser(User user) {
log.info("Creating user: {}", user.getUsername());
try {
// 业务逻辑
log.debug("User created successfully");
} catch (Exception e) {
log.error("Failed to create user", e);
}
}
}
高级特性
1. 注解组合
// 标准实体类模板
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // JPA 要求
@AllArgsConstructor
@Builder
@ToString(exclude = {"password", "salt"})
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@EqualsAndHashCode.Include
private Long id;
@Column(unique = true, nullable = false)
private String username;
@Column(nullable = false)
private String email;
private String password;
private String salt;
@Builder.Default
@Column(name = "created_at")
private LocalDateTime createdAt = LocalDateTime.now();
}
2. 自定义 Builder
@Builder
public class CustomBuilder {
private String name;
private int age;
// 自定义 Builder 方法
public static class CustomBuilderBuilder {
public CustomBuilderBuilder ageBetween(int min, int max) {
if (age < min || age > max) {
throw new IllegalArgumentException("Age out of range");
}
return this;
}
}
}
3. 延迟初始化
public class LazyExample {
@Getter(lazy = true)
private final Map<String, String> cachedData = initCache();
private Map<String, String> initCache() {
Map<String, String> map = new HashMap<>();
// 昂贵的初始化操作
return Collections.unmodifiableMap(map);
}
}
框架集成
1. Spring Boot 集成
// application.properties
lombok.anyConstructor.addConstructorProperties=true
// Entity
@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
private String name;
@Min(0)
private BigDecimal price;
}
// Service
@Slf4j
@Service
@RequiredArgsConstructor
public class ProductService {
private final ProductRepository repository;
@Transactional
public Product createProduct(ProductDTO dto) {
log.info("Creating product: {}", dto.getName());
Product product = Product.builder()
.name(dto.getName())
.price(dto.getPrice())
.build();
return repository.save(product);
}
}
2. Jackson 集成
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse<T> {
private boolean success;
private String message;
private T data;
@JsonProperty("timestamp")
@Builder.Default
private LocalDateTime timestamp = LocalDateTime.now();
public static <T> ApiResponse<T> ok(T data) {
return ApiResponse.<T>builder()
.success(true)
.data(data)
.build();
}
}
3. MapStruct 集成
// DTO
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserDTO {
private Long id;
private String username;
private String email;
}
// Entity
@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
public class UserEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String email;
}
// Mapper
@Mapper(componentModel = "spring")
public interface UserMapper {
UserEntity toEntity(UserDTO dto);
UserDTO toDto(UserEntity entity);
List<UserDTO> toDtoList(List<UserEntity> entities);
}
配置和优化
1. lombok.config 配置文件
# 项目根目录下的 lombok.config
lombok.anyConstructor.addConstructorProperties = true
lombok.accessors.chain = true
lombok.accessors.fluent = true
lombok.equalsAndHashCode.callSuper = call
lombok.extern.findbugs.addSuppressFBWarnings = true
lombok.toString.callSuper = call
# 日志配置
lombok.log.fieldName = LOG
lombok.log.fieldIsStatic = true
2. 链式调用
// 配置:lombok.accessors.chain = true
@Data
@Accessors(chain = true) // setter 返回 this
public class ChainExample {
private String name;
private int age;
// 使用
// ChainExample obj = new ChainExample()
// .setName("John")
// .setAge(30);
}
// Builder 链式调用
@Builder
@Accessors(chain = true)
public class Product {
private Long id;
private String name;
// 链式 Builder
// Product product = Product.builder()
// .id(1L)
// .name("Phone")
// .build();
}
常见问题解决方案
1. JPA 实体循环引用
@Entity
@Getter
@Setter
@ToString(exclude = {"department"})
public class Employee {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
}
@Entity
@Getter
@Setter
@ToString(exclude = {"employees"})
public class Department {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "department")
private List<Employee> employees;
}
2. 继承问题
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseEntity {
private Long id;
private LocalDateTime createdAt;
}
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class User extends BaseEntity {
private String username;
private String email;
// 包含父类字段的 equals/hashCode/toString
}
3. Builder 默认值
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Order {
private Long id;
@Builder.Default
private OrderStatus status = OrderStatus.PENDING;
@Builder.Default
private LocalDateTime orderTime = LocalDateTime.now();
@Singular("item")
private List<String> items;
}
性能优化技巧
1. 懒加载优化
public class PerformanceExample {
// 延迟初始化大对象
@Getter(lazy = true)
private final ExpensiveObject expensive = initExpensive();
// 延迟初始化集合
@Getter
private final List<String> data = new ArrayList<>();
public void addData(String item) {
synchronized (data) {
data.add(item);
}
}
}
2. 缓存 hashCode
@Data
@EqualsAndHashCode(cacheStrategy = EqualsAndHashCode.CacheStrategy.LAZY)
public class LargeEntity {
private Long id;
private String field1;
// ... 很多字段
// hashCode 只计算一次并缓存
}
IDE 配置
IntelliJ IDEA
- 安装插件:Lombok Plugin
- 启用注解处理:
Settings → Build, Execution, Deployment → Compiler → Annotation Processors → Enable annotation processing - 查看生成的代码:
- Structure 视图查看生成的方法
- 使用
Show Bytecode查看字节码
Eclipse
- 下载 lombok.jar
- 运行安装:
java -jar lombok.jar - 指定 Eclipse 路径安装
- 重启 Eclipse
Maven/Gradle 配置
Maven
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
</dependencies>
<!-- 可选:编译时注解处理 -->
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.11.0</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
Gradle
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'
// 测试环境也需要
testCompileOnly 'org.projectlombok:lombok:1.18.30'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.30'
}
// 或者使用插件
plugins {
id 'io.freefair.lombok' version '8.4'
}
最佳实践总结
1. 实体类标准模板
// JPA Entity
@Entity
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@Builder
@ToString(exclude = {"关联字段"})
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Table(name = "table_name")
public class EntityClass {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@EqualsAndHashCode.Include
private Long id;
// 业务字段
}
// DTO
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DTOClass {
private Long id;
private String name;
}
// 配置类
@ConfigurationProperties(prefix = "app")
@Data
@Validated
public class ConfigClass {
@NotNull
private String apiKey;
@Min(1)
private int timeout;
}
2. 避免的陷阱
- ❌ 不要在 JPA 实体上使用
@Data(使用循环引用问题) - ❌ 不要在继承链中忘记
callSuper = true - ❌ 不要在有 final 字段的类上使用
@Data而不初始化 - ✅ 使用
@ToString.Exclude排除敏感字段 - ✅ 使用
@Builder.Default设置默认值 - ✅ 为测试添加
@NoArgsConstructor
3. 团队规范
# 团队统一的 lombok.config
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true
lombok.anyConstructor.addConstructorProperties = true
lombok.equalsAndHashCode.callSuper = call
lombok.toString.callSuper = call
lombok.accessors.chain = true
# 日志配置
lombok.log.fieldName = log
迁移指南
从传统代码迁移
// 之前
public class OldUser {
private Long id;
private String name;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
// ... 更多 getter/setter
@Override
public String toString() { /* 手动实现 */ }
@Override
public boolean equals(Object o) { /* 手动实现 */ }
@Override
public int hashCode() { /* 手动实现 */ }
}
// 之后
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class NewUser {
private Long id;
private String name;
// 所有方法自动生成
}
Lombok 通过减少样板代码,让 Java 开发更高效、代码更简洁,是现代 Java 开发的重要工具。正确使用可以显著提升开发效率和代码质量。