Lombok — 代码简化神器
Lombok 通过注解在编译期自动生成样板代码(getter/setter/构造器/equals/hashCode 等),大幅减少冗余代码。
安装
xml
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional> <!-- 编译期依赖,不传递 -->
</dependency>IDE 需要安装 Lombok 插件(IntelliJ IDEA 内置支持)。
核心注解
java
// @Data = @Getter + @Setter + @ToString + @EqualsAndHashCode + @RequiredArgsConstructor
@Data
public class User {
private Long id;
private String name;
private String email;
private Integer age;
}
// 等价于手写:
public class User {
private Long id;
// ... 其他字段
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() { ... }
// 无参构造器(因为没有 final 字段)
public User() {}
}构造器注解
java
// @NoArgsConstructor — 无参构造器
// @AllArgsConstructor — 全参构造器
// @RequiredArgsConstructor — final 字段和 @NonNull 字段的构造器
@Data
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
public class Product {
@NonNull
private Long id; // RequiredArgsConstructor 包含
@NonNull
private String name; // RequiredArgsConstructor 包含
private String description; // RequiredArgsConstructor 不包含
private BigDecimal price;
}
// 使用
Product p1 = new Product(); // 无参
Product p2 = new Product(1L, "iPhone", "desc", new BigDecimal("999")); // 全参
Product p3 = new Product(1L, "iPhone"); // Required 参数@Builder — 建造者模式
java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Order {
private Long id;
private Long userId;
private String status;
@Builder.Default // 设置默认值
private LocalDateTime createTime = LocalDateTime.now();
@Singular // 支持单个添加
private List<OrderItem> items;
}
// 使用
Order order = Order.builder()
.id(1L)
.userId(100L)
.status("PENDING")
.item(new OrderItem(1L, "iPhone", 1)) // @Singular 生成 item() 方法
.item(new OrderItem(2L, "AirPods", 2))
.build();
// 继承时的 Builder
@Data
@EqualsAndHashCode(callSuper = true)
@SuperBuilder // 支持继承的 Builder
public class VipUser extends User {
private String vipLevel;
}@Value — 不可变对象
java
// @Value = @Getter + @ToString + @EqualsAndHashCode + @AllArgsConstructor + final 字段
@Value
public class Money {
BigDecimal amount;
String currency;
}
// 等价于:
public final class Money {
private final BigDecimal amount;
private final String currency;
public Money(BigDecimal amount, String currency) { ... }
public BigDecimal getAmount() { return amount; }
public String getCurrency() { return currency; }
// equals, hashCode, toString
}
Money price = new Money(new BigDecimal("99.99"), "CNY");
// price.setAmount(...); // 编译错误,没有 setter@Slf4j — 日志
java
// @Slf4j 自动注入 log 字段
@Slf4j
@Service
public class UserService {
public User getUser(Long id) {
log.debug("查询用户, id={}", id);
User user = userRepo.findById(id).orElse(null);
if (user == null) {
log.warn("用户不存在, id={}", id);
}
return user;
}
}
// 等价于:
// private static final Logger log = LoggerFactory.getLogger(UserService.class);
// 其他日志注解
@Log4j2 // Log4j2
@Log // java.util.logging
@CommonsLog // Apache Commons Logging@SneakyThrows — 隐藏受检异常
java
// 将受检异常包装为非受检异常(谨慎使用)
@SneakyThrows(IOException.class)
public String readFile(String path) {
return Files.readString(Path.of(path)); // 不需要 try-catch
}
// 等价于:
public String readFile(String path) {
try {
return Files.readString(Path.of(path));
} catch (IOException e) {
throw Lombok.sneakyThrow(e); // 绕过编译器检查
}
}@Cleanup — 自动关闭资源
java
// 自动调用 close() 方法
public void processFile(String path) throws IOException {
@Cleanup InputStream in = new FileInputStream(path);
@Cleanup OutputStream out = new FileOutputStream(path + ".bak");
// 方法结束时自动关闭,等价于 try-with-resources
byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
}与 Spring 集成的最佳实践
java
// Spring 推荐:构造器注入 + @RequiredArgsConstructor
@Service
@RequiredArgsConstructor // 自动生成包含 final 字段的构造器
@Slf4j
public class OrderService {
private final OrderRepository orderRepo; // final → 构造器注入
private final UserService userService; // final → 构造器注入
private final EmailService emailService; // final → 构造器注入
public Order createOrder(CreateOrderRequest req) {
log.info("创建订单, userId={}", req.getUserId());
// ...
}
}
// DTO 使用 @Data + @Builder
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserVO {
private Long id;
private String name;
private String email;
// 从 Entity 转换
public static UserVO from(User user) {
return UserVO.builder()
.id(user.getId())
.name(user.getName())
.email(user.getEmail())
.build();
}
}注意事项
java
// ❌ @Data 用于 JPA 实体类有风险
// @EqualsAndHashCode 默认包含所有字段,可能导致懒加载问题
@Data // 不推荐用于 JPA 实体
@Entity
public class User { ... }
// ✅ JPA 实体推荐写法
@Entity
@Getter
@Setter
@NoArgsConstructor
@EqualsAndHashCode(of = "id") // 只用 id 比较
@ToString(exclude = {"orders"}) // 排除关联集合,避免懒加载
public class User { ... }
// ❌ @Builder 与 @Data 同时使用时,@Builder 会覆盖无参构造器
// 需要显式加 @NoArgsConstructor @AllArgsConstructor
@Data
@Builder
@NoArgsConstructor // 必须显式添加
@AllArgsConstructor // @Builder 需要全参构造器
public class Product { ... }Lombok 使用建议
- 实体类(Entity):
@Getter @Setter @NoArgsConstructor @EqualsAndHashCode(of="id") - DTO/VO:
@Data @Builder @NoArgsConstructor @AllArgsConstructor - Service:
@RequiredArgsConstructor @Slf4j - 不可变值对象:
@Value - 避免在 JPA 实体上用
@Data