专栏:《从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 APIOptional

在此之前,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篇

 

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐