JAVA重点基础、进阶知识及易错点总结(36)Lombok 实战 + 阶段总结

🚀 Java 巩固进阶 · 第 36 天

主题:Lombok 实战 + 阶段总结 ------ 解放双手,高效开发

📅 进度概览 :今天是 设计模式与注解阶段(31-36 天)的最后一天 ,也是 Java 基础巩固阶段的收官之日!学习 Lombok 提升开发效率,并全面复盘本阶段知识。

💡 核心价值

  • 效率提升:用注解自动生成 get/set/构造器,减少 80% 样板代码。
  • 代码整洁:类只关注业务逻辑,不含 getter/setter 等噪音代码。
  • 原理理解:了解注解处理器(APT)工作机制,深化对编译期的理解。
  • 阶段复盘:梳理设计模式与注解知识体系,为 SpringBoot 学习做好准备。

一、Lombok 核心注解:一行顶百行 🛠️

1. 什么是 Lombok?

复制代码
┌─────────────────────────────────────┐
│  🔄 Lombok 本质                       │
│  是一个注解库,编译时自动生成代码     │
│                                      │
│  • 减少样板代码(get/set/构造器等)  │
│  • 通过注解处理器(APT)实现         │
│  • 编译后字节码包含生成的代码        │
└─────────────────────────────────────┘

2. 核心注解速查表(⭐ 必背)

注解 作用 等价手写代码 使用频率
@Data 生成 get/set/toString/equals/hashCode 全部 ⭐⭐⭐⭐⭐
@Getter/@Setter 生成 get 或 set 方法 get/set 方法 ⭐⭐⭐⭐
@NoArgsConstructor 生成无参构造器 public Class() {} ⭐⭐⭐⭐
@AllArgsConstructor 生成全参构造器 public Class(所有字段) {} ⭐⭐⭐⭐
@RequiredArgsConstructor 生成 required 构造器(final 字段) public Class(final 字段) {} ⭐⭐⭐
@Builder 生成建造者模式代码 Builder 内部类 ⭐⭐⭐⭐
@ToString 生成 toString 方法 toString() 方法 ⭐⭐⭐
@EqualsAndHashCode 生成 equals/hashCode equals/hashCode() 方法 ⭐⭐⭐
@Slf4j 生成 log 日志对象 private static final Logger... ⭐⭐⭐⭐⭐

3. 实战对比:手写 vs Lombok

java 复制代码
// ❌ 传统手写(约 50 行代码)
public class User {
    private Long id;
    private String name;
    private Integer age;
    
    public User() {}
    
    public User(Long id, String name, Integer age) {
        this.id = id;
        this.name = name;
        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; }
    public Integer getAge() { return age; }
    public void setAge(Integer age) { this.age = age; }
    
    @Override
    public String toString() {
        return "User{id=" + id + ", name=" + name + ", age=" + age + "}";
    }
    
    @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);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

// ✅ Lombok 版(约 10 行代码)
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class User {
    private Long id;
    private String name;
    private Integer age;
}

💡 效率对比

  • 代码量减少 80%+
  • 可读性提升 50%+
  • 维护成本降低 70%+

二、Lombok 原理:注解处理器(APT)🔍

1. 编译流程图解

复制代码
源码 (.java + Lombok 注解)
    ↓
javac 编译
    ↓
注解处理器 (Lombok APT)
    ↓
生成代码 (get/set/构造器等)
    ↓
合并到抽象语法树 (AST)
    ↓
生成字节码 (.class)
    ↓
运行时:普通 Java 类(无 Lombok 依赖)

2. 关键特性

java 复制代码
// ✅ 编译时生成:运行时没有 Lombok 依赖
// ✅ 字节码完整:IDE 和运行时都能正常调用 get/set
// ✅ 无性能损耗:生成的代码与手写等价

// ⚠️ 注意:
// 1. IDE 需安装 Lombok 插件(否则提示找不到方法)
// 2. 编译时需添加 Lombok 依赖
// 3. 反编译.class 文件能看到生成的方法

3. Maven/Gradle 配置

xml 复制代码
<!-- Maven 依赖 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.30</version>
    <scope>provided</scope>
</dependency>
gradle 复制代码
// Gradle 依赖
compileOnly 'org.projectlombok:lombok:1.18.30'
annotationProcessor 'org.projectlombok:lombok:1.18.30'

三、⚠️ 注意事项与避坑指南

1. 常见坑点

java 复制代码
// ❌ 坑 1:@Data + 继承 = equals/hashCode 问题
@Data
public class Parent { private String name; }

@Data
public class Child extends Parent { private Integer age; }
// 问题:子类 equals 不包含父类字段

// ✅ 解决:用 @EqualsAndHashCode(callSuper = true)
@Data
@EqualsAndHashCode(callSuper = true)
public class Child extends Parent { ... }

// ❌ 坑 2:@Builder + @NoArgsConstructor 冲突
@Builder
public class User { ... }
// 问题:@Builder 会生成全参构造,与无参构造冲突

// ✅ 解决:显式添加 @NoArgsConstructor
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User { ... }

// ❌ 坑 3:@Data + JPA 实体 = 性能问题
@Data
@Entity
public class UserEntity { ... }
// 问题:@Data 生成的 equals/hashCode 可能导致懒加载触发

// ✅ 解决:JPA 实体只生成 getId 的 equals/hashCode
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@Data
@Entity
public class UserEntity {
    @EqualsAndHashCode.Include
    private Long id;
}

2. 最佳实践建议

场景 推荐注解 说明
普通 DTO/VO @Data 最常用,生成全部方法
实体类(JPA) @Getter/@Setter + 自定义 @EqualsAndHashCode 避免懒加载问题
不可变对象 @Value 类似 @Data,但字段默认 final
构建复杂对象 @Builder 链式调用,代码优雅
日志对象 @Slf4j 自动生成 log 对象

四、🎯 今日实战任务:Lombok 重构练习

任务 1:用 Lombok 重构用户类

java 复制代码
/**
 * 要求:
 * 1. 找到之前手写的 User 类(含 get/set/构造器/toString)
 * 2. 用 @Data @NoArgsConstructor @AllArgsConstructor 替代
 * 3. 添加 @Builder,测试链式创建对象
 * 4. 添加 @Slf4j,在方法中使用 log.info()
 * 
 * 💡 提示:
 * 确保 IDE 已安装 Lombok 插件
 * 编译后反编译.class 文件,查看生成的方法
 */

任务 2:Lombok 与继承

java 复制代码
/**
 * 业务场景:父类 + 子类的 equals/hashCode 问题
 * 
 * 要求:
 * 1. 创建 Parent 类(@Data,含 name 字段)
 * 2. 创建 Child 类继承 Parent(@Data,含 age 字段)
 * 3. 测试:两个 Child 对象,name 和 age 相同,equals 是否返回 true?
 * 4. 用 @EqualsAndHashCode(callSuper = true) 修复问题
 * 
 * 💡 思考:
 * 为什么子类 equals 默认不包含父类字段?
 */

任务 3:Lombok 与 JPA 实体

java 复制代码
/**
 * 业务场景:Spring Data JPA 实体类
 * 
 * 要求:
 * 1. 创建 UserEntity 类,添加 @Entity @Id 注解
 * 2. 使用 @Getter/@Setter 替代 @Data
 * 3. 使用 @EqualsAndHashCode(onlyExplicitlyIncluded = true)
 * 4. 只将 id 字段包含在 equals/hashCode 中
 * 
 * 💡 提示:
 * 这是 SpringBoot + JPA 的最佳实践
 */

任务 4:Lombok 原理探索

java 复制代码
/**
 * 要求:
 * 1. 创建一个简单的 @Data 类
 * 2. 编译项目,找到生成的.class 文件
 * 3. 用反编译工具(如 IDEA 内置或 javap)查看字节码
 * 4. 记录:生成了哪些方法?与手写的是否一致?
 * 
 * 💡 命令:
 * javap -c -p User.class
 */

📝 第 36 天 · 核心总结(极简背诵版)

  1. Lombok 核心注解

    java 复制代码
    @Data              // get/set/toString/equals/hashCode
    @Builder           // 建造者模式
    @NoArgsConstructor // 无参构造
    @AllArgsConstructor// 全参构造
    @Slf4j            // 日志对象
  2. Lombok 原理

    复制代码
    注解处理器(APT)→ 编译时生成代码 → 合并到 AST → 生成字节码
    运行时无 Lombok 依赖,无性能损耗
  3. 避坑指南

    复制代码
    继承:@EqualsAndHashCode(callSuper = true)
    JPA 实体:避免@Data,用@Getter/@Setter + 自定义 equals
    Builder 冲突:同时加 @NoArgsConstructor
  4. 最佳实践

    • ✅ DTO/VO 用 @Data
    • ✅ 实体类用 @Getter/@Setter + 自定义 @EqualsAndHashCode
    • ✅ 日志用 @Slf4j
    • ❌ 避免过度使用,关键逻辑仍需手写

🎉 恭喜!Java 基础巩固阶段(1-36 天)正式完结!

📊 完整知识地图复盘

复制代码
📅 第 1 阶段:Java 基础巩固(1-36 天)
│
├─ 📚 第 1-6 天:语法与面向对象
│   ├─ 数据类型/流程控制/数组/字符串
│   ├─ 封装/继承/多态/抽象类/接口
│   └─ 异常处理体系
│
├─ 📦 第 7-12 天:集合框架
│   ├─ List (ArrayList/LinkedList)
│   ├─ Set (HashSet/TreeSet)
│   ├─ Map (HashMap/ConcurrentHashMap)
│   └─ 泛型与工具类
│
├─ 📁 第 13-18 天:IO 流与日期时间
│   ├─ 字节流/字符流/缓冲流/转换流
│   ├─ File 文件操作
│   └─ JDK8 日期 API(LocalDate/DateTimeFormatter)
│
├─ 🧵 第 19-24 天:多线程与反射
│   ├─ 线程创建/同步/通信/线程池
│   ├─ Callable/Future/CompletableFuture
│   ├─ 反射基础 (Class/Field/Method)
│   └─ 反射进阶 + 注解初探
│
├─ 🆕 第 25-30 天:JDK8+ 新特性
│   ├─ Lambda 表达式
│   ├─ Stream 流式编程
│   ├─ Optional 空值处理
│   ├─ 接口默认/静态方法
│   └─ JDK9-11 新特性
│
└─ 🏗️ 第 31-36 天:设计模式与注解
    ├─ 单例/工厂/建造者/原型
    ├─ 代理/装饰器
    ├─ 注解基础与自定义
    ├─ 注解 + 反射实战
    └─ Lombok 高效开发

📝 高频面试题清单(自测 30 题)

分类 面试题
集合 HashMap 底层结构?JDK7 与 JDK8 区别?
集合 ArrayList 扩容机制?LinkedList 适用场景?
集合 ConcurrentHashMap 如何保证线程安全?
并发 synchronized 与 ReentrantLock 区别?
并发 volatile 关键字作用?能保证原子性吗?
并发 线程池 7 大参数?拒绝策略有哪些?
并发 ThreadLocal 原理?内存泄漏问题?
IO BIO/NIO/AIO 区别?
IO 缓冲流为什么比普通流快?
JDK8 Lambda 表达式本质?函数式接口有哪些?
JDK8 Stream 中间操作与终止操作区别?
JDK8 Optional 使用禁忌?
反射 反射获取 Class 的三种方式?
反射 反射破坏单例如何防御?
设计模式 单例模式几种实现?双重检查锁为什么需要 volatile?
设计模式 工厂模式与抽象工厂区别?
设计模式 代理模式与装饰器模式区别?
设计模式 JDK 动态代理与 CGLIB 区别?
注解 元注解有哪些?@Retention 三种策略区别?
注解 如何通过反射读取注解信息?
其他 String 为什么不可变?
其他 == 与 equals() 区别?
其他 接口与抽象类区别?
其他 重载与重写区别?
其他 深克隆与浅克隆区别?
其他 检查异常与非检查异常区别?
其他 final/finally/finalize 区别?
其他 静态方法与实例方法区别?
其他 序列化与反序列化?serialVersionUID 作用?
其他 Java 反射的性能开销及优化?

恭喜你完成了 Java 基础的系统性巩固!继续加油!💪✨

相关推荐
鹿角片ljp1 小时前
KV Cache 解析
java·算法
captain3762 小时前
网络原理(9)-数据链路层
java·网络协议·java-ee
惊讶的猫2 小时前
意图识别置信度和检索重排的分数
java
2601_966949652 小时前
只拿到股票代码还不够:量化程序到底还需要哪些标的信息?——从数据建模开始理解股票元数据
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
caoerzhong2 小时前
仓库管理数字化趋势解读:JeeWMS 开源 Java WMS 视角下的五个演进方向
java·开源
m0_734571763 小时前
深入理解5g <十八>传输块tbsize的计算
开发语言·5g
程序员JerrySUN3 小时前
Jetson Edge AI 实战01:Nano、Xavier、Orin 怎么选?Jetson 硬件选型详解【视频讲解】
java·数据库·redis·安全·mybatis
Joy T4 小时前
Spring AI 2.0 Agent 进阶:Memory、State 与 Context Engineering 常见技术全景
java·人工智能·后端·spring·agent入门·agent state
估值探索者4 小时前
【Python量化系统工程化 #08】关了 SSH 就停?systemd 让脚本开机自启 + 异常自动拉起
java·c++·人工智能·分类·数据挖掘