跳到主要内容

JEP 223:新版本字符串方案

概括

定义一个版本字符串方案,可以轻松区分主要版本、次要版本和安全更新版本,并将其应用到 JDK。

目标

  • 易于人类理解,易于程序解析。

  • 与当前的行业实践保持一致,特别是语义版本控制

  • 可供现有的打包系统和平台部署机制采用,包括RPMdpkgIPSJava 网络启动协议 (JNLP)

  • 消除当前将两种类型的信息编码在版本字符串的一个元素中的做法,,次要版本号和安全级别,这种做法难以破译并导致跳过许多版本号。

  • 提供简单的 API 用于版本字符串解析、验证和比较。

非目标

  • 更改此 JEP 目标版本之前的任何版本使用的版本字符串格式。

动机

哪个版本包含所有最新的安全修复程序:JDK 7 Update 55 还是 JDK 7 Update 60?

看起来 JDK 7 Update 60 比 Update 55 晚了五个版本,因此它必须包含更多安全修复程序,对吗?

遗憾的是,这个结论是不正确的:这两个版本都包含完全相同的安全修复程序。要理解这个答案,您首先需要了解JDK 更新版本的当前编号方案。包含安全修复之外的更改的次要版本是 20 的倍数。基于先前次要版本的安全版本是奇数,增加 5,或在必要时增加 6,以保持更新编号为奇数。要了解次要版本是否实际上比早期版本更安全,最终需要查看发行说明或源代码。

名为“JDK 7 Update 60”、“1.7.0_60”和“JDK 7u60”的版本之间有什么区别?

这些只是同一版本的不同名称。这些差异使得识别和验证等效版本变得困难。对已解析标记序列进行简单的逐点比较是不够的;相反,需要相当复杂的算法。小写“u”的使用不是行业标准,也不是语言中立的。

更简单、更直观的版本控制方案已经过去很久了。

描述

版本号

_版本号_是由$VNUM句点字符 (U+002E) 分隔的非空元素序列。元素要么为零,要么是不带前导零的无符号整数。版本号中的最后一个元素不得为零。格式为:

[1-9][0-9]*((\.0)*\.[1-9][0-9]*)*

该序列可以是任意长度,但前三个元素被赋予特定含义,如下所示:

$MAJOR.$MINOR.$SECURITY
  • $MAJOR--- 主要版本号,对于包含 Java SE 平台规范新版本中指定的重要新功能的主要版本递增,例如, Java SE 8 的JSR 337。在给定的情况下,功能可能会在主要版本中删除提前通知至少一个主要版本,并且在合理的情况下可以进行不兼容的更改。$MAJORJDK 8 的版本号是8$MAJORJDK 9 的版本号是9。当$MAJOR递增时,所有后续元素都将被删除。

  • $MINOR--- 次要版本号,针对次要更新版本递增,该次要更新版本可能包含兼容的错误修复、相关平台规范的维护版本强制要求的标准 API 的修订以及该规范范围之外的实现功能,例如新的 JDK -特定的 API、额外的服务提供程序、新的垃圾收集器以及新硬件架构的端口。

  • $SECURITY--- 安全级别,针对包含关键修复(包括提高安全性所需的修复)的安全更新版本而增加。递增时$SECURITY不会重置为零。因此,对于给定值,$MINOR较高的 值始终表示更安全的发布,无论 的值如何。$SECURITY``$MAJOR``$MINOR

版本号的第四个及后面的元素可供 JDK 代码库的下游消费者免费使用。这样的消费者可以_例如_使用第四元素来识别除了相应安全版本中的安全修复之外还包含少量关键非安全修复的补丁版本。

版本号不包含尾随零元素;$SECURITY如果它的值为零,则被省略;$MINOR如果$MINOR$SECURITY的值都为零,则被省略。

版本号中的数字序列以数字、逐点的方式与另一个此类序列进行比较;例如9.9.1小于9.10.3。如果一个序列比另一个序列短,则较短序列的缺失元素被认为小于较长序列的相应元素;例如9.1.2小于9.1.2.1

版本字符串

版本_字符串_,$VSTR包含版本号$VNUM,如上所述,可选地后跟预发布和构建信息,采用以下格式之一:

$VNUM(-$PRE)?\+$BUILD(-$OPT)?
$VNUM-$PRE(-$OPT)?
$VNUM(+-$OPT)?

在哪里:

  • $PRE, 匹配([a-zA-Z0-9]+)--- 预发布标识符。通常ea,对于正在积极开发且可能不稳定的早期访问版本,或者internal对于内部开发人员构建。

    比较两个版本字符串时,具有预发布标识符的字符串始终小于具有相同$VNUM但没有此类标识符的字符串。当预发布标识符仅包含数字时,按数字进行比较,否则按字典顺序进行比较。数字标识符被认为小于非数字标识符。

  • $BUILD, 匹配(0|[1-9][0-9]*)--- 内部版本号,针对每个升级的内部版本递增。 当 的任何部分增加$BUILD时重置为 1 。$VNUM

    $VNUM当比较两个具有相等和分量的版本字符串时$PRE,没有分量的字符串$BUILD总是小于有分量的字符串$BUILD;否则,$BUILD对数字进行数值比较。

  • $OPT,匹配([-a-zA-Z0-9\.]+)--- 如果需要的话,附加构建信息。对于构建,internal这通常包含构建的日期和时间。

    比较两个版本字符串时, 的值$OPT(如果存在)可能重要也可能不重要,具体取决于所选的比较方法。

版本号与和10-ea匹配。版本号与和匹配。$VNUM = "10"``$PRE = "ea"``10+-ea``$VNUM = "10"``$OPT = "ea"

下表使用现有格式和建议格式比较了 JDK 9 的潜在版本字符串:

Existing                Proposed
Release Type long short long short
------------ -------------------- --------------------
Early Access 1.9.0-ea-b19 9-ea 9-ea+19 9-ea
Major 1.9.0-b100 9 9+100 9
Security #1 1.9.0_5-b20 9u5 9.0.1+20 9.0.1
Security #2 1.9.0_11-b12 9u11 9.0.2+12 9.0.2
Minor #1 1.9.0_20-b62 9u20 9.1.2+62 9.1.2
Security #3 1.9.0_25-b15 9u25 9.1.3+15 9.1.3
Security #4 1.9.0_31-b08 9u31 9.1.4+8 9.1.4
Minor #2 1.9.0_40-b45 9u40 9.2.4+45 9.2.4

作为参考,此表显示了新格式的版本字符串,因为它们假设用于某些 JDK 7 更新和安全版本:

Actual               Hypothetical
Release Type long short long short
------------ -------------------- -------------------
Security 2013/04 1.7.0_21-b11 7u21 7.4.10+11 7.4.10
Security 2013/06 1.7.0_25-b15 7u25 7.4.11+15 7.4.11
Minor 2013/09 1.7.0_40-b43 7u40 7.5.11+43 7.5.11
Security 2013/10 1.7.0_45-b18 7u45 7.5.12+18 7.5.12
Security 2014/01 1.7.0_51-b13 7u51 7.5.13+13 7.5.13
Security 2014/04 1.7.0_55-b13 7u55 7.5.14+13 7.5.14
Minor 2014/05 1.7.0_60-b19 7u60 7.6.14+19 7.6.14
Security 2014/07 1.7.0_65-b20 7u65 7.6.15+20 7.6.15

1从版本号中删除初始元素

1该提案删除了JDK 版本号中的初始元素。也就是说,它表明 JDK 9 的第一个版本将具有版本号9.0.0而不是1.9.0.0.

近二十年后,很明显当前版本号方案的第二个元素是 JDK_事实上的_ $MAJOR版本号。当我们添加重要的新功能以及进行不兼容的更改时,我们会增加该元素。

我们可以开始将当前方案的初始元素视为$MAJOR版本号,但是 JDK 9 将具有版本号,2.0.0即使每个人都已经将其称为“JDK 9”。这对任何人都没有帮助。

如果我们保留初始版本号,那么 JDK 版本号将继续违反语义版本控制1的原则,并且刚接触 Java 的开发人员将继续对_例如_、和之间的区别感到困惑。1.9``9

1放弃初始.存在一些风险。比较版本号的方法有很多种;有些可以正常工作,有些则不能。

  • 通过解析元素并进行数字比较来比较版本号的现有代码将继续工作,因为 9 大于 1;9.0.0将被视为晚于1.8.0

  • 当初始元素具有值时跳过初始元素的现有代码1也将继续工作,因为在新方案中初始元素永远不会具有该值。

  • 然而,假设初始元素具有值 的现有代码1,因此在比较版本号时始终跳到第二个元素,将无法正常工作;例如,此类代码将考虑9.0.1放在前面1.8.0

轶事证据表明,第三类中的现有代码并不常见,但我们欢迎相反的数据。

应用程序编程接口

将定义一个简单的 Java API 来解析、验证和比较版本字符串(8072379、8144062

package java.lang;

import java.util.Optional;

public class Runtime {

public static Version version();

public static class Version
implements Comparable<Version>
{

public static Version parse(String);

public int major();
public int minor();
public int security();

public List<Integer> version();
public Optional<String> pre();
public Optional<Integer> build();
public Optional<String> optional();

public int compareTo(Version o);
public int compareToIgnoreOpt(Version o);

public boolean equals(Object o);
public boolean equalsIgnoreOpt(Object o);

public String toString();
public int hashCode();
}
}

将定义等效的 C API,很可能根据修订后的jvm_version_info 结构体来定义。

JDK 中检查和比较 JDK 版本字符串的所有代码都将更新为使用这些 API。我们鼓励其库或应用程序检查和比较 JDK 版本字符串的开发人员使用这些 API。

系统属性

以下系统属性返回的值由该 JEP 修改。一般语法如下:

Name                            Syntax
------------------------------ --------------
java.version $VNUM(\-$PRE)?
java.runtime.version $VSTR
java.vm.version $VSTR
java.specification.version $VNUM
java.vm.specification.version $VNUM

系统属性java.class.version不受影响。

下表显示了不同版本类型的现有值和建议值:

System Property                   Existing      Proposed
------------------------------- ------------ --------
Early Access
java.version 1.9.0-ea 9-ea
java.runtime.version 1.9.0-ea-b73 9-ea+73
java.vm.version 1.9.0-ea-b73 9-ea+73
java.specification.version 1.9 9
java.vm.specification.version 1.9 9

Major (GA)
java.version 1.9.0 9
java.runtime.version 1.9.0-b100 9+100
java.vm.version 1.9.0-b100 9+100
java.specification.version 1.9 9
java.vm.specification.version 1.9 9

Minor #1 (GA)
java.version 1.9.0_20 9.1.2
java.runtime.version 1.9.0_20-b62 9.1.2+62
java.vm.version 1.9.0_20-b62 9.1.2+62
java.specification.version 1.9 9
java.vm.specification.version 1.9 9

Security #1 (GA)
java.version 1.9.0_5 9.0.1
java.runtime.version 1.9.0_5-b20 9.0.1+20
java.vm.version 1.9.0_5-b20 9.0.1+20
java.specification.version 1.9 9
java.vm.specification.version 1.9 9

请注意,历史上在任何这些系统属性中作为版本标识的一部分检测到的所有代码.都需要进行检查并可能进行修改。例如,System.getProperty("java.version").indexof('.')将返回-1主要版本。

启动器

在 OpenJDKjava启动器实现中,报告版本信息时会使用系统属性,例如java -versionjava -fullversionjava -showversion

启动器输出继续取决于系统属性,如下所示:

$ java -version
openjdk version \"${java.version}\"
${java.runtime.name} (build ${java.runtime.version})
${java.vm.name} (build ${java.vm.version}, ${java.vm.info})

$ java -showversion < ... >
openjdk version \"${java.version}\"
${java.runtime.name} (build ${java.runtime.version})
${java.vm.name} (build ${java.vm.version}, ${java.vm.info})
[ ... ]

$ java -fullversion
openjdk full version \"${java.runtime.version}\"

实现细节可以在源代码中找到。

@sinceJavaDoc 标签

JavaDoc 标记的值@since将继续与系统属性保持一致java.specification.version;因此,新的 JDK 9 API 将由 表示@since 9

Mercurial 变更集标签

Mercurial 标签用于识别促销的变更集。Code Tool 的 jcheck等工具用于验证推送到 JDK 发布林的所有变更集,这些工具将得到增强,以支持使用新版本方案的标签。

Mercurial 标签的一般语法是jdk\-$VNUM\+$BUILD。下表显示了不同版本类型的建议值:

Release Type      Proposed
---------------- -----------
Major (GA) jdk-9+100
Minor #1 (GA) jdk-9.1.2+27
Security #1 (GA) jdk-9.0.1+3

某些工具可能需要支持现有的和建议的标签格式。

测试

更改版本字符串的语法和语义将需要对所有组件区域进行广泛的测试。独立于 JDK 版本字符串的现有测试应该继续通过。