冷知识:Java -version发生了哪些变化?

257 阅读3分钟

在日常开发中,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.110 是主版本,0 是 interim,1 是 update;
  • 引入发布日期 2018-04-17,提升透明度;
  • 构建号(如 +10)仍保留,用于精确追踪构建。

JEP 322 的版本号设计配合 JDK 每半年发布一次的节奏,使得版本之间的关系一目了然,便于用户、工具和运维系统识别和管理。


👨‍💻版本演进对开发者的影响

JDK 版本java -version 输出示例格式变化
JDK 81.8.0_251旧格式
JDK 99JEP 223 引入新结构
JDK 1010.0.1JEP 322 调整结构,更贴合时间线

对开发者的建议:

  • 使用脚本或工具解析 java -version 时注意适配新旧格式;
  • 工具链升级时建议使用 JDK 提供的 java.lang.Runtime.Version API 获取结构化版本号;
  • 结合构建号(+build)和发布日期可实现更精细的版本控制。

📝结语

JEP 223 和 JEP 322 体现了 Java 生态对现代化、自动化运维和版本管理的持续改进。对于开发者而言,理解版本号背后的语义,有助于更精准地选择、升级和调试 JDK 版本,也有助于构建更健壮的工具链和系统。


同时,随着Java版本的不断演进,未来或许还会出现新的版本号提案与变更。开发者应持续关注官方文档与社区动态,及时掌握最新变化,从而更好地应对开发过程中可能出现的版本适配等问题。

如果你对版本号策略还有疑问,欢迎留言交流!