Java Lombok 详解

25 阅读5分钟

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

  1. 安装插件:Lombok Plugin
  2. 启用注解处理
    Settings → Build, Execution, Deployment → Compiler → Annotation Processors
    → Enable annotation processing
    
  3. 查看生成的代码
    • Structure 视图查看生成的方法
    • 使用 Show Bytecode 查看字节码

Eclipse

  1. 下载 lombok.jar
  2. 运行安装java -jar lombok.jar
  3. 指定 Eclipse 路径安装
  4. 重启 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 开发的重要工具。正确使用可以显著提升开发效率和代码质量。