Day1:Java语言发展简史:从1到JDK 24,我们经历了什么
专栏:《从CRUD到AI工程师的完整跃迁路径》 第1篇/共90篇
下篇预告:《Lambda表达式彻底理解:不只是语法糖》——我们会深入拆解Lambda的底层实现(invokedynamic指令)、对比性能差异,以及函数式接口在业务代码里的20种实战写法。
2015年,在一家公司任职,组里有个小伙子问我:"梁哥,项目还在跑JDK 6,外面的世界都JDK 8了,我们什么时候升级?"
我说快了。然后拖到了2017年。
那次升级后,我才真正意识到:你对Java版本演进的理解深度,直接决定了你做技术决策的底气。
很多干了三五年的兄弟写代码写得很溜,但问他JDK 8和JDK 11到底有什么区别,支支吾吾说不出三个。这不是技术问题,是视角问题——你写代码十年,都没抬头看过路在哪。
这篇文章,我带你从Java 1.0一路走到JDK 24。不展开每个版本的全部特性(那得写一本书),只抓四个关键节点:JDK 8、11、17、21。这四个版本是整个Java生态的转折点,剩下的版本,要么是铺垫,要么是延伸。
作为Java工程师,你现在正处在技术视野快速打开的阶段。别急着追热点语言,先把Java的家底摸透——从JDK 1.0到JDK 24,这30年的演进里藏着无数设计决策的取舍,那才是真正值钱的东西。
一、从Applet谈起:Java的"远古时期"(1995-2013)
1995年,Sun公司发布Java 1.0。那会儿Java的卖点是什么?"Write Once, Run Anywhere"——一次编写,到处运行。JVM这个"虚拟机"概念,在当时是革命性的。
Java真正火起来,靠的是两件事:Applet和Servlet。
Applet让网页能跑Java程序,在那个Flash都还没普及的年代,这玩意炫得很。而Servlet让Java进了后端,成了企业级开发的标配。
但2000年以后,Java进入了一段很长的"平庸期"。JDK 1.4、JDK 5(泛型)、JDK 6、JDK 7——版本在升,但多是修修补补。那种感觉怎么说呢,就像一个中年男人在还房贷,每天按部就班,没啥惊喜。
直到2014年。
二、JDK 8(2014.3):Java的"文艺复兴"
如果Java历史上只能记一个版本,那就是JDK 8。
它带来了三个改变Java编程范式的核心特性:Lambda表达式、Stream API、Optional。
在此之前,Java的函数式编程基本靠"匿名内部类"硬撑。给你看一段对比就清楚了:
JDK 7 vs JDK 8:一个排序的差距
// JDK 7 写法 —— 匿名内部类,七行代码
List<String> names = Arrays.asList("张三", "李四", "王五", "赵六");
Collections.sort(names, new Comparator<String>() {
@Override
public int compare(String a, String b) {
return a.length() - b.length();
}
});
// JDK 8 写法 —— Lambda,一行搞定
names.sort((a, b) -> a.length() - b.length());
这就是JDK 8给Java带来的最大改变:从命令式编程走向声明式编程。你不再命令机器"一步一步怎么做",而是声明"我要什么结果"。代码的可读性和可维护性上了不止一个台阶。
还有Optional。它硬生生把NullPointerException从"运行时炸弹"变成了"编译期你不得不处理它"。这种"用类型系统约束程序员行为"的设计思想,在你遇到JDK 17的密封类时会再次看到。
JDK 8是Java的"文艺复兴"——它没有抛弃过去,但给未来画了方向。
三、JDK 11(2018.9):模块化与LTS的分水岭
JDK 9引入了模块化系统(JPMS,Java Platform Module System),但JDK 9是个非LTS短期版本,真正让模块化落地的是JDK 11。
你要理解模块化的意义,得先知道一个痛:JAR地狱。当你项目引了100个依赖时,每个依赖都把自己的实现细节暴露在外面,类冲突、找不到类、版本不兼容——这些是Java工程师的日常噩梦。
模块化做了什么?显式声明"我暴露什么"和"我需要什么"。
// module-info.java —— 模块描述文件
module com.example.myapp {
// 我需要这些模块
requires java.sql;
requires spring.boot;
requires lombok;
// 我只暴露这个包给外部
exports com.example.myapp.api;
// opens 允许反射访问(给框架用)
opens com.example.myapp.model to spring.core;
}
有了模块系统,你的代码边界从"约定"变成了"强制"。内部实现类,外部根本无法访问——不是靠"大家约定好不调那个包",而是编译器直接报错。
JDK 11还带来一个容易被忽略但非常实用的特性:新的HTTP Client API。
// 以前发HTTP请求要不就HttpURLConnection(难用),要不就引Apache HttpClient(重)
// JDK 11 直接用标准库搞定
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users"))
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
JDK 11也是一条分水岭:从此以后,Oracle JDK开始收费了。 很多人搞不清楚Oracle JDK和OpenJDK的关系,借这个机会说清楚:
- Oracle JDK:Oracle的商业版本,用于生产环境需付费(开发/测试免费)。每三年一次LTS。
- OpenJDK:开源免费版本,Oracle、Red Hat、Amazon、阿里都提供各自的OpenJDK发行版(Oracle OpenJDK / Adoptium / Corretto / Dragonwell)。
- 实质差异非常小,对99%的项目来说,用哪个OpenJDK发行版都一样。
如果你公司还在用Oracle JDK 8,记得确认一下是不是该换成OpenJDK了——这笔钱省下来够买好几台服务器。
四、JDK 17(2021.9):新一代LTS,生态成熟的标志
如果说JDK 8重新定义了Java怎么写,JDK 17重新定义了Java怎么"管"。
JDK 17最大的亮点是模式匹配(Pattern Matching)和密封类(Sealed Classes)。这不是语法糖,这是对类型系统的一次"收紧"。
看看模式匹配怎么把instanceof从啰嗦变成简洁:
// JDK 16 之前:先 instanceof,再手动强转
if (obj instanceof String) {
String s = (String) obj;
System.out.println(s.toUpperCase());
}
// JDK 16+ 模式匹配:一步到位,类型绑定
if (obj instanceof String s) {
System.out.println(s.toUpperCase());
}
// 结合 switch 的模式匹配(JDK 17+)
String result = switch (obj) {
case Integer i -> "整数: " + i;
case String s -> "字符串长度: " + s.length();
case List<?> l -> "列表有 " + l.size() + " 个元素";
case null -> "nulll值";
default -> "未知类型";
};
这种语法乍看只是"少写几行",但你要意识到它背后传递的信号:Java的类型检查从运行时走向编译时。模式匹配让你在写代码时就把所有可能的类型分支都覆盖掉,漏一个编译器就提示你——这就是编译器给你当安全网。
密封类也是同样的逻辑:
// 密封类:明确规定谁能继承我
public sealed interface Payment permits Alipay, WechatPay, BankTransfer {
void pay(BigDecimal amount);
}
// 这三个实现类都在同一个模块内,外部无法新增 Payment 的实现
public record Alipay(String account) implements Payment { ... }
public record WechatPay(String openId) implements Payment { ... }
public record BankTransfer(String bankCard) implements Payment { ... }
以前你用Enum来保证值的安全,现在用sealed class来保证类型体系的安全。这在金融、电商这种对状态流转有严格要求的领域特别实用——支付类型就这三种,不允许任何地方悄悄冒出一个第四种。
JDK 17为什么重要?因为它证明了Java已经完成了从"修修补补"到"持续进化"的转型。 从JDK 9开始,Java改成每半年发一个新版本。很多人抱怨"版本太多追不上",但恰恰是这种节奏,让Java从沉睡的巨人变成了敏捷的运动员。
五、JDK 21(2023.9):虚拟线程,改写并发底层逻辑
如果你问我JDK 8以来最激动人心的特性是什么,我会说虚拟线程(Virtual Threads)。
在JDK 21之前,Java的并发模型是"一个任务一个平台线程"。平台线程是操作系统的线程,创建和切换都很昂贵。你开1000个线程,系统就开始喘了;开10000个,大概率直接崩。
虚拟线程改变了这个等式。虚拟线程不映射到操作系统线程,而是由JVM在一个很小的平台线程池上调度。 创建100万个虚拟线程?可以,代价极低。
// 平台线程方式:开10000个线程,内存和CPU都很吃力
try (var executor = Executors.newFixedThreadPool(100)) {
for (int i = 0; i < 10000; i++) {
int taskId = i;
executor.submit(() -> {
callRemoteService(taskId); // 阻塞I/O,平台线程干等着
});
}
}
// 虚拟线程方式:开10000个虚拟线程,JVM内部用少量平台线程调度
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
for (int i = 0; i < 10000; i++) {
int taskId = i;
executor.submit(() -> {
callRemoteService(taskId); // 阻塞I/O时,虚拟线程被挂起,平台线程去跑别的
});
}
}
这套机制对代码是透明的——你写代码的方式基本不变,但底层线程模型完全不同。虚拟线程把Java从"IO密集型场景性能焦虑"中解放出来。
很多人问我:"梁哥,虚拟线程出来以后,Reactive编程(WebFlux)还有必要学吗?"
我的回答是:短期共存,长期趋向。 虚拟线程解决了Reactive解决的核心问题(线程阻塞成本高),但写法比Reactive友好太多——你不需要学Mono/Flux那一套。对于绝大多数业务场景,虚拟线程 + 简单的同步写法就是最优解。Reactive还会在特定场景有价值(比如事件流处理),但不会再是"解决高并发的唯一答案"。
六、JDK 24(2025.3)与未来
JDK 24刚刚发布不久,主要延续了前几个版本的路线:继续优化虚拟线程、扩展模式匹配、GC精进。还有一个值得关注的方向是Vector API(向量计算)和GraalVM原生镜像的结合——这在AI推理部署场景下有巨大的应用潜力。
Vector API让JVM能够利用CPU的SIMD指令集做并行数值计算。说人话就是:原来你用循环一个一个算的东西,现在可以一次算一片。这对AI模型推理、科学计算等场景是实打实的性能提升。
但说实话,目前JDK 24和更早的JDK 22、23都算"过渡版本"。真正的下一个战略级LTS很可能是JDK 25(预计2025年9月)。
代码写得再多,都不如读懂一次JEP的进化逻辑。
下篇预告:《Lambda表达式彻底理解:不只是语法糖》——我们会深入拆解Lambda的底层实现(invokedynamic指令)、对比性能差异,以及函数式接口在业务代码里的20种实战写法。
专栏:《从CRUD到AI工程师的完整跃迁路径》 | 作者·老梁 | 第1篇/共90篇
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)