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-20131995年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 82014.3Java的文艺复兴如果Java历史上只能记一个版本那就是JDK 8。它带来了三个改变Java编程范式的核心特性Lambda表达式、Stream API、Optional。在此之前Java的函数式编程基本靠匿名内部类硬撑。给你看一段对比就清楚了JDK 7 vs JDK 8一个排序的差距// JDK 7 写法 —— 匿名内部类七行代码 ListString names Arrays.asList(张三, 李四, 王五, 赵六); Collections.sort(names, new ComparatorString() { 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 112018.9模块化与LTS的分水岭JDK 9引入了模块化系统JPMSJava 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(); HttpResponseString response client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body());JDK 11也是一条分水岭从此以后Oracle JDK开始收费了。很多人搞不清楚Oracle JDK和OpenJDK的关系借这个机会说清楚Oracle JDKOracle的商业版本用于生产环境需付费开发/测试免费。每三年一次LTS。OpenJDK开源免费版本Oracle、Red Hat、Amazon、阿里都提供各自的OpenJDK发行版Oracle OpenJDK / Adoptium / Corretto / Dragonwell。实质差异非常小对99%的项目来说用哪个OpenJDK发行版都一样。如果你公司还在用Oracle JDK 8记得确认一下是不是该换成OpenJDK了——这笔钱省下来够买好几台服务器。四、JDK 172021.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 212023.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 242025.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篇