在日常开发中,java -version 命令是我们验证 JDK 安装与版本的常用方式。然而,如果你从 JDK 8 升级到 JDK 9 或 JDK 10,就会注意到这个命令的输出格式发生了显著变化。本文将带你深入了解这些变化背后的两个关键提案:🟥JEP 223:新的版本字符串方案 和 🟥JEP 322:时间驱动的版本号方案。
⏮️JDK 8 及之前的版本号体系
在 JDK 8 及之前,Java 使用传统的版本号格式:1.<major>.0_<update>。例如:
$ java -version
java version "1.8.0_251"
Java(TM) SE Runtime Environment (build 1.8.0_251-b08)
Java HotSpot(TM) 64-Bit Server VM (build 25.251-b08, mixed mode)
我们一张图来看下jdk8的版本组成:
graph TD
A["java version \"1.8.0_251\""] --> B["Major Version: 1"]
B --> C["Minor Version: 8 (代表 JDK 8)"]
C --> D["Security/Update Number: 0"]
D --> E["Build/Update Patch: _251"]
subgraph 说明
Bdesc["历史兼容性保留,不再递增"]
Cdesc["JDK 的实际主版本"]
Ddesc["功能与安全更新的组合"]
Edesc["特定构建或补丁号"]
end
B --> Bdesc
C --> Cdesc
D --> Ddesc
E --> Edesc
图中结构如下:
-
🟥Major Version: 1 这是历史遗留版本前缀,从 JDK 1.0 一直沿用。
-
🟥Minor Version: 8 表示这是 JDK 8,是开发者最常关注的部分 👀。
-
🟥Security/Update Number: 0
表示这是该主版本的首次发布或没有功能性更新。
-
🟥Build/Update Patch: _251
表示第 251 个更新版本,主要用于修复 bug 或安全补丁 🛠️。
这套版本号格式存在几个问题:
1.前缀冗余,但一直保留出于兼容考虑;- 更新号(如
_251)混合了安全更新与功能更新; - 无法清晰表达重大、次要、补丁和快速安全补丁的区别。
🚀 JEP 223: 新的版本字符串方案(JDK 9)
从 JDK 9 开始,Java 引入了 JEP 223,引入了更清晰、语义化的版本号格式:
<feature>.<interim>.<update>.<patch>
各部分含义:
feature: 主版本号,通常每六个月更新一次;interim: 次版本号,保留将来扩展功能但不破坏兼容性;update: 安全和稳定性更新;patch: 紧急补丁,如重大安全漏洞修复。
我们再用一张图看下:
graph TD
A["java version \"9.0.0.0\""] --> B["Feature: 9"]
B --> C["Interim: 0"]
C --> D["Update: 0"]
D --> E["Patch: 0"]
A --> F["Build Number: +181"]
subgraph 说明
Bdesc["主版本号,表示重大功能版本(例如 JDK 9)"]
Cdesc["次版本号,保留将来用于非兼容性增强"]
Ddesc["安全或稳定性更新"]
Edesc["紧急补丁或小修复"]
Fdesc["构建号,用于唯一标识构建版本"]
end
B --> Bdesc
C --> Cdesc
D --> Ddesc
E --> Edesc
F --> Fdesc
示例(JDK 9):
$ java -version
java version "9"
Java(TM) SE Runtime Environment (build 9+181)
Java HotSpot(TM) 64-Bit Server VM (build 9+181, mixed mode)
变更要点:
- 不再使用
1.前缀; - 明确版本号与构建号(如
+181)分离; - 输出更清晰、规范。
⏱️JEP 322:时间驱动的版本号方案(JDK 10)
随着 Java 采用 半年发布节奏(6-month cadence),需要一个能支持快速迭代、简单明确的版本号策略。JEP 322 提出了时间驱动的版本号体系,它简化了 JEP 223 中的四段式结构,主要使用三段:
<feature>.<interim>.<update>
其中 patch 仍保留但较少使用。
一张图来看懂新的版本组成:
graph TD
A["java version '17.0.10' 2024-01-16 LTS"] --> B["Feature: 17"]
B --> C["Interim: 0"]
C --> D["Update: 1"]
A --> E["Build Number: +10"]
A --> F["Release Date: 2018-04-17"]
subgraph 说明
Bdesc["主版本号,表示 JDK 17"]
Cdesc["次版本号,通常为 0,保留扩展用"]
Ddesc["更新号,表示常规安全或错误修复"]
Edesc["构建号,用于唯一标识构建版本"]
Fdesc["发布日期,明确该版本何时发布"]
end
B --> Bdesc
C --> Cdesc
D --> Ddesc
E --> Edesc
F --> Fdesc
示例(JDK 10):
$java -version
java version "17.0.10" 2024-01-16 LTS
Java(TM) SE Runtime Environment (build 17.0.10+11-LTS-240)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.10+11-LTS-240, mixed mode, sharing)
变更说明:
10.0.1中10是主版本,0是 interim,1是 update;- 引入发布日期
2018-04-17,提升透明度; - 构建号(如
+10)仍保留,用于精确追踪构建。
JEP 322 的版本号设计配合 JDK 每半年发布一次的节奏,使得版本之间的关系一目了然,便于用户、工具和运维系统识别和管理。
👨💻版本演进对开发者的影响
| JDK 版本 | java -version 输出示例 | 格式变化 |
|---|---|---|
| JDK 8 | 1.8.0_251 | 旧格式 |
| JDK 9 | 9 | JEP 223 引入新结构 |
| JDK 10 | 10.0.1 | JEP 322 调整结构,更贴合时间线 |
对开发者的建议:
- 使用脚本或工具解析
java -version时注意适配新旧格式; - 工具链升级时建议使用 JDK 提供的
java.lang.Runtime.VersionAPI 获取结构化版本号; - 结合构建号(+build)和发布日期可实现更精细的版本控制。
📝结语
JEP 223 和 JEP 322 体现了 Java 生态对现代化、自动化运维和版本管理的持续改进。对于开发者而言,理解版本号背后的语义,有助于更精准地选择、升级和调试 JDK 版本,也有助于构建更健壮的工具链和系统。
同时,随着Java版本的不断演进,未来或许还会出现新的版本号提案与变更。开发者应持续关注官方文档与社区动态,及时掌握最新变化,从而更好地应对开发过程中可能出现的版本适配等问题。
如果你对版本号策略还有疑问,欢迎留言交流!