Java 这门语言,一句话定位:"写一次,到处跑;写在企业里,跑在服务器上"。它不花哨、不炫技,胜在稳定、坑少、人多、资料多。本页以 JDK 21 LTS 为学习基线,新特性一路讲到 JDK 25 LTS(2025 年 9 月发布)。学完这一页,你能独立写出一个控制台小项目,并听得懂同事说"这个 NPE 是哪来的"。
本节目录
- 为什么学 Java + JDK/JRE/JVM + 环境搭建 + Hello World
- 基础语法:变量、类型、流程控制、switch 新写法
- 面向对象:类、封装继承多态、接口、record
- 集合框架与 Stream API
- 泛型:通配符与类型擦除
- 异常处理:try-catch 与 try-with-resources
- IO 与 NIO:读写文件
- 并发编程:线程池、锁、虚拟线程
- JVM 入门:内存、GC、类加载
- 新特性速览:sealed、模式匹配、文本块
- 小项目实战:学生成绩管理系统(控制台版)
- 设计模式:七个最常用的套路
- 常见坑与最佳实践
- 构建工具 Gradle:依赖、版本目录与依赖锁定
- JIT 与字节码深入:javap、分层编译、逃逸分析与 JMH
- JPMS 模块系统:module-info、exports/opens 与 jlink
- 注解处理器:APT 与 kapt/KSP
第 1 节 · 最新版本与兼容性:选哪个 JDK,别被版本号绕晕
Oracle 从 2017 年(JDK 10 起)改成每 6 个月发一个新版本,但只有 LTS(Long-Term Su
第 2 节 · 为什么学 Java,以及把环境跑起来
先泼一盆冷水:Java 不是"最好玩"的语言,语法啰嗦、样板代码多,写个空 main 都要整行 public stati
第 3 节 · 基础语法:变量、类型、流程控制
这一章是"认字"阶段。Java 语法比 Python 啰嗦,但啰嗦有啰嗦的好处——类型明确,bug 提前暴露。下面把最常
第 4 节 · 面向对象:Java 的灵魂
Java 是纯面向对象语言(基本类型除外)。所谓"面向对象",人话就是:把现实世界的东西,抽象成"类"(图纸),再按图纸
第 5 节 · 集合框架:装一堆数据的工具箱
数组能装东西,但长度定死了、不方便增删。集合框架(Collections Framework)就是 Java 提供的"动
第 6 节 · 泛型:给集合贴个"内容标签"
上面代码里的 List
第 7 节 · 异常处理:程序出错了怎么办
程序跑挂了,不能直接蓝屏给用户看。异常(Exception)机制就是 Java 的"保险丝":出错时抛出一个异常对象,你
第 8 节 · IO 与 NIO:读写文件
程序要跟硬盘打交道:读配置文件、写日志、导出报表。Java 的 IO 体系乍一看类名一大堆,其实分两派:字节流(Inpu
第 9 节 · 并发编程:让程序同时干多件事
单核时代程序一次只干一件事,像一个厨师炒菜。多核时代你要开多个线程(Thread),像开多个灶台同时炒。但线程不是免费的
第 10 节 · JVM 入门:Java 程序住在哪里
面试必问、线上排障必备。你不用手写 JVM,但要知道对象住哪、垃圾谁收、类怎么加载这三件事。理解了它们,遇到"内存溢出
第 11 节 · 新特性速览:别停在 Java 8
很多老教程还停在 Java 8(2014 年)。其实 JDK 21/25 加了一大批让代码更短、更安全的特性。下面挑五个
第 12 节 · 小项目实战:学生成绩管理系统(控制台版)
学了一堆零件,拼个真东西才算数。下面这个控制台小程序,把前面的集合、record、IO、Scanner 输入、多线程全串
第 13 节 · 设计模式:七个最常用的套路
设计模式不是玄学,是前人踩坑后总结的"代码怎么组织才好改"。别去背那 23 种,先把下面七个真正天天用的吃透:单例、工厂
第 14 节 · 常见坑与最佳实践
这一章是"老司机的血书"——每一条都是前人踩过、线上出过事的坑。收藏下来,写完代码对照一遍,能避开 80% 的低级错误。
第 15 节 · 构建工具 Gradle:把依赖、编译、测试、打包串成
前面 13 章你写的都是"单个 .java 文件 + javac"。可一旦项目里出现 十几个 jar 依赖、三个模块、还
第 16 节 · JIT 与字节码深入:Java 到底是怎么变快的
第 9 章讲了 JVM 的内存和 GC,这一章往下再钻一层:你的 .java 文件到底变成了什么,又是怎么从"慢吞吞的解
第 17 节 · JPMS 模块系统:从 classpath 到 mo
JDK 9 引入的模块系统(JPMS,JSR 376)是 Java 二十多年来最大的一次架构变动。它想解决一个很朴素的问
第 18 节 · 注解处理器:在编译期就把代码写出来
你写 @Data 就白得一堆 getter;写一个接口,MapStruct 就帮你生成实现类;写 @Inject,Dag
综合练习题:把全书串起来
下面 5 道题把全书知识点串一遍。先自己写代码,再展开答案对。别一上来就看答案——看了等于没做。
1.(Stream 实战)给定 List<Employee>,每个 Employee 有 name、dept、salary。写一段 Stream:过滤出工资 > 10000 的员工,按部门分组,算出每个部门的平均工资。
查看答案与参考代码
答案:
Map<String, Double> avgByDept = employees.stream()
.filter(e -> e.salary() > 10000)
.collect(Collectors.groupingBy(
Employee::dept,
Collectors.averagingDouble(Employee::salary)
));
解析:groupingBy 第二个参数是 downstream collector,averagingDouble 直接算平均值,不用手动 reduce。
2.(并发实战)要并发下载 10 个网页,每个下载完打印标题。用 CompletableFuture 写,要求全部完成后再打印"全部下载完"。
查看答案与参考代码
答案:
List<CompletableFuture<String>> futures = urls.stream()
.map(url -> CompletableFuture.supplyAsync(() -> downloadTitle(url), pool))
.toList();
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenRun(() -> System.out.println("全部下载完"))
.join();
解析:allOf 等所有任务完成,thenRun 接一个无参回调。注意 toArray(new CompletableFuture[0]) 是类型安全写法。
3.(JVM 排障)线上服务每隔几分钟卡 2 秒,日志里看到 Pause Full (System.gc())。最可能是什么原因?怎么修?
查看答案
答案:有代码或调用的库显式调用了 System.gc(),触发 Full GC。修法:① 启动参数加 -XX:+DisableExplicitGC 屏蔽;② 找到调用处(用 jstack 或 Arthas),改掉。别让业务代码随便触发 Full GC。
4.(泛型 + PECS)写一个方法 copy(List<? super Dog> dest, List<? extends Dog> src),把 src 里的狗拷到 dest。解释为什么参数这么写。
查看答案与参考代码
答案:
static void copyDogs(List<? super Dog> dest, List<? extends Dog> src) {
for (Dog d : src) { // src 是生产者,extends:往外读
dest.add(d); // dest 是消费者,super:往里写
}
}
解析:src 可能是 List<Puppy>,只能用 extends Dog 读;dest 可能是 List<Animal>,用 super Dog 才能往里塞 Dog。这就是 PECS。
5.(综合)写一个程序:用虚拟线程并发处理 1000 个文件,每个文件读出来统计字数,最后汇总总字数。要求异常不中断其他任务。
查看答案与参考代码
答案:
try (var exec = Executors.newVirtualThreadPerTaskExecutor()) {
List<Future<Long>> futures = files.stream()
.map(f -> exec.submit(() -> {
try { return Files.readString(f).length(); }
catch (IOException e) { return 0L; } // 单个失败不影响整体
}))
.toList();
long total = 0;
for (Future<Long> fu : futures) total += fu.get();
System.out.println("总字数:" + total);
}
解析:虚拟线程 + try-catch 包住单个任务,一个文件读失败返回 0 不影响其他。try 结束自动等所有虚拟线程结束。