使用 JDK 中可用的预览功能

 

预览功能以提高其质量

数百万人在生产中依赖 Java 来处理关键工作负载,Java 的影响力是全球性的。鉴于其深度和广度,新功能不仅需要以清晰完整的方式设计,还需要以可靠且可维护的方式实现。提供给 Java 开发人员在生产中使用的所有新功能都必须达到最高质量。因此,为开发人员提供对新功能的初步访问至关重要,以鼓励反馈——反馈将有助于完善这些功能并达到其最终和永久形式的预期质量水平。

有几类新的非最终功能

  1. 预览,用于完全指定和实现但仍需调整的新 Java 平台功能
  2. 实验性,主要用于 HotSpot JVM 中的新功能
  3. 孵化(也称为孵化器模块),用于潜在的新 API 和 JDK 工具

以下是一些遵循上述过程的当前功能示例

  1. switch 表达式是一种语言功能。它最初在 Java 12 中预览。它的第二个版本在 Java 13 中预览。然后它在 Java 14 中成为永久功能。
  2. Z 垃圾收集器是 HotSpot 功能。它从 Java 11 到 Java 14 都是实验性的,并在 Java 15 中成为生产功能。
  3. HTTP/2 客户端 API 是一个 API,在 Java 9 和 Java 10 中作为孵化功能添加,然后在 Java 11 中成为标准功能。

此外,还有其他不属于上述三类中的非最终功能,您将在后面看到。

 

使用 JDK 增强提案 (JEP) 管理新功能

新功能几乎总是从 JDK 增强提案 (JEP) 开始,这是一种定义明确的机制,用于管理非平凡的 JDK 增强,例如以下内容

  1. Java 语言功能,用于Java 语言规范,例如文本块或记录。

  2. 核心 Java 平台中的Java SE API 功能,例如java.lang.Objectjava.lang.Stringjava.io.File。此类 API 功能将驻留在名称以 java 开头的模块中。

  3. 具有其他 JDK 特定功能的JDK API 功能,例如 JDK Flight Recorder。此类 API 功能将驻留在名称以jdk 开头的模块中。

  4. JDK 工具功能,例如jshelljlink

  5. 特定于 HotSpot JVM 的功能,即 Java 虚拟机的 OpenJDK 实现。这两个功能是应用程序类数据共享和 Z 垃圾收集器 (ZGC)。

您可以在此图像中看到这些关系

Preview, Experimental, Incubating

重要性如何?如果对增强有很高的需求,如果它影响 JDK 或 JDK 本身开发的流程和基础设施(例如将 JDK 源代码存储库迁移到 GitHub),或者仅仅因为它需要相当多的工程投资,那么它就是非平凡的。

弃用功能和改进现有功能也通过 JEP 流程进行。

大多数大型功能的引入使用两阶段方法,该方法使用 JEP,从初步访问阶段开始,然后是激活阶段。在您有权访问非最终功能的初步访问阶段期间,可能存在一个或多个迭代。在初步访问阶段(或阶段)期间,鼓励您积极使用非最终功能并获得经验,以便提供反馈。

如果您提供的反馈突出显示了一些改进空间,那么下一次迭代可以解决这些问题。此反馈还可能导致文档改进,例如通常伴随新语言功能的程序员指南、新 API 的 Javadoc 示例或常见问题解答页面。

最后,当一项新功能被认为已准备好时,最终阶段将把该新功能过渡到 Java 平台中的永久功能。

谁应该提供反馈?好吧,工程师欢迎来自您(Java 开发人员,例如关于新 API)、工具供应商(例如关于新 JDK 工具)等的反馈。最终,所有建设性和可操作的反馈都是受欢迎的。

如果您打算提供反馈,请通过官方渠道进行。在社交网络上发布的评论可能很有趣,但也可能很快消失,以至于无法被合适的人看到。这就是为什么每个 JEP 都明确指定了一个邮件列表来收集反馈。例如,JEP 384 关于记录(当时是第二次预览,但现在是最终版本)要求使用amber-dev 邮件列表 提供反馈。

本质上,Java 工程师正在寻找对新功能的真实世界经验和可操作反馈,方法是尽早以非最终形式提供这些功能,并在这些功能成为 Java 平台的最终和永久部分之前进行任何必要的调整。

 

预览功能

Java 语言功能和 Java API 功能具有很大的曝光率,任何设计上的错误都可能产生负面后果。为了避免这种风险,一个特定的 JEP (JEP 12)(以及信息性 JEP)提供了预览新 Java 语言和 Java API 功能的能力。

预览功能是指被认为已完全指定和实现但可能在最终和永久地包含在 Java 平台中之前仍会发生变化的功能。您的反馈将被评估并用于在功能成为永久功能之前进行最终调整。

例如,Amber 项目 是一个 OpenJDK 项目,其目标是通过 Java 语言的演变来提高开发人员的生产力。Amber 利用预览功能机制将标准永久功能逐步交付到 Java 平台。下表显示了 X 轴上的 Java 版本和 Y 轴上的 Amber 功能。您可能会看到,通常两轮预览足以在将新功能永久化之前收集可操作的反馈,但并非总是如此。

Amber in Action

Amber 项目将发布更多功能,您可以在Amber 项目页面 上查看它们。可能存在较小的 Amber 功能或更改,这些功能或更改不会使用 JEP,因为 JEP 仅用于需要大量工程工作量的功能。

要深入了解,请考虑 switch 表达式,它是在 Amber 项目的保护下开发的,该项目在Java 12 (JEP 325) 和Java 13 (JEP 354) 中预览,然后在Java 14 (JEP 361) 中成为标准语言功能。

Java 12 中,break 关键字用于为 switch 表达式生成值。您的反馈表明,这种对break 的使用令人困惑。作为回应,它被yield 关键字替换。

Java 14 中的最终 switch 表达式保留了在Java 13 中预览的yield 方法。虽然预览功能旨在非常接近最终版本,但更改仍然可能。只有Java 14 中 switch 表达式的最终版本才受长期兼容性规则的约束。

 

实验性功能

实验性功能是一种测试平台机制,用于收集对非平凡 HotSpot 增强功能的反馈。与JEP 12 用于预览功能不同,没有 JEP 管理实验性功能;实验性功能的过程更像是一种既定的 HotSpot 约定,而不是正式流程。

以 Z 垃圾收集器为例。ZGC 提供低延迟垃圾收集暂停时间,低于 10 毫秒,但通常更接近 2 毫秒,无论堆大小如何,即使堆小到几兆字节,或大到几太字节。

ZGC 团队多次利用实验性功能机制,ZGC 最初在 JDK 11 中作为一项实验性功能引入,仅限于 Linux x64 (JEP 333)。从那时起,ZGC 添加了其他改进(例如,并发类卸载、内存取消提交和更多平台),同时其他 ZGC 功能也得到了完善。

在这些迭代期间收集的总体反馈和经验使 ZGC 能够逐步巩固到现在具有 HotSpot 功能所需的较高质量的程度。因此,JEP 377Java 15 中正式将 ZGC 转换为常规 HotSpot 生产功能。

 

孵化器模块

JEP 11 引入了孵化的概念,以允许包含 JDK API 和 JDK 工具,这些 API 和工具可能有一天(经过改进和稳定后)会被包含和支持在 Java 平台或 JDK 中。

例如,HTTP/2 客户端 API 已经通过JEP 110 在 JDK 9 和 JDK 10 中作为 JDK 特定 API 孵化,最终离开了孵化阶段,并作为标准 Java API 包含在Java 11 (JEP 321) 中。

 

使用预览功能

重要的安全措施可以防止开发人员意外使用非最终功能。这是必要的,因为非最终功能在以后的 Java 功能版本中成为最终和永久功能时,很可能会有所不同。此外,只有最终的永久功能才受 Java 严格的向后兼容性规则的约束。

因此,为了避免无意使用,预览和实验性功能默认情况下处于禁用状态,并且 JDK 文档明确警告您有关这些功能及其任何相关 API 的非最终性质。

预览功能特定于给定的 Java 功能版本,并且需要在编译时以及运行时使用特殊标志。

以下示例显示了如何使用基于在Java 16 中预览的功能的预览功能。

假设您需要评估JEP 397 中描述的密封类。(注意:密封类现在已成为JEP 409 的永久功能)

让我们创建以下Shape 密封接口。

public sealed interface Shape
        permits Square, Circle {

    double surface();
}

您需要一个第一个强制性Square 类,您需要将其存储在与Shape 接口相同的包或模块中。

public final class Square implements Shape {

    private double width;

    public Square(double width) {
        this.width = width;
    }

    public double surface() {
        return width*width;
    }
}

以及第二个强制性Circle 类。

public final class Circle implements Shape {

    private double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    public double surface() {
        return Math.PI*radius*radius;
    }
}

如果您使用以下经典命令编译这些类

> javac *.java

您将收到以下错误消息

Shape.java:1: error: '{' expected
public interface Shape
                      ^
1 error

您收到此消息是因为permits关键字在 Java 16 中不存在。要编译此类,您需要声明要激活预览功能才能使其正常工作。假设您使用的是 JDK 16,正确的命令如下。

> javac --enable-preview --release 16 *.java

然后编译将成功,并显示以下消息,警告您使用预览功能。

Note: Shape.java uses preview language features.
Note: Recompile with -Xlint:preview for details.

让我们创建以下使用这些类的类。

public class Main {
    
    public static void main(String... args) {
        Circle circle = new Circle(1.0d);
        Square square = new Square(1.0d);
        System.out.println("Circle: " + circle.surface());
        System.out.println("Square: " + square.surface());
    }
}

使用启用预览功能的 Java 16 编译后,您可以键入以下内容来运行此类

java --enable-preview Main

以下行将打印在控制台上。

Circle: 3.141592653589793
Square: 1.0

大多数 IDE 支持使用预览功能,这不仅允许您在您最喜欢的 IDE 中使用预览功能,而且还有助于这些 IDE 在这些功能成为永久性和最终功能后不久支持这些功能。

顺便说一句,需要非最终功能的工件不应分发。例如,不要在 Maven Central 上分发利用预览功能的工件,因为该工件只能在特定 Java 功能版本上运行。

 

使用实验性功能

实验性功能是 JVM 功能,默认情况下处于禁用状态;-XX:+UnlockExperimentalVMOptions 标志指示 HotSpot 允许使用实验性功能。然后可以通过特定标志启用实际的实验性功能。例如,在 Java 15 之前,当 ZGC 仍然是实验性功能时,您可以使用 -XX:+UseZGC 来激活它。

 

使用孵化器模块

最后,孵化器模块也受到保护,防止意外使用,因为孵化只能在jdk.incubator 命名空间中进行。因此,类路径上的应用程序必须使用--add-modules 命令行选项来明确请求对孵化功能的解析。或者,模块化应用程序必须直接指定对孵化功能的依赖项或传递依赖项。

 

使用早期访问版本评估项目

LoomPanamaValhalla 是 OpenJDK 长期项目的示例。这些项目的目的是在特定领域进行基础调查,以彻底改进(或彻底改造)Java 平台的某些方面。例如,Loom 的目标是通过使线程更轻量级且更易于使用,为 Java 平台带来更大的并发性。

鉴于其雄心勃勃的范围,这些项目将在多个 Java 功能版本中迭代地交付多个功能,这些功能共同解决了所解决的领域。为此,将进行各种调查,将开发不同的原型来试验潜在的解决方案,并且某些方法可能会被放弃或重新构思。

正如您所料,这项工作需要时间,并且需要大量的工程工作。在这些项目的支持下开发的新功能无法利用常规的反馈机制;因为它们只是未完成的,所以它们没有预期的稳定性。这并不意味着使用反馈没有价值。相反,早期反馈可能会影响一些设计讨论并验证早期原型。

为了尽早收集此类反馈,有时会为新功能提供特定的早期访问版本,同时进行设计和开发。此类偶尔的特定于功能的早期访问 (EA) JDK 版本的独特目标仅仅是允许专家用户尽早测试特定新功能。

鉴于 EA 版本的目标受众是高度熟练但有限的,项目负责人有权放宽某些规则(例如,在兼容性方面)或施加约束(例如,允许新功能的某些方面部分缺失)。例如,第一个 Loom EA 版本出现在 2019 年 7 月;第二个 EA 版本在六个月后出现。用项目负责人的话说,第二个版本“与第一个 EA 版本中的 API 大相径庭”,这表明早期访问功能不受任何兼容性规则的约束。这也再次确认,EA 版本应仅由专家用户在特定 EA 版本的范围内测试新功能。

JDK 早期访问版本可从jdk.java.net 获取。除了对 EA 版本进行范围界定并记录限制和已知问题外,下载页面还指定了用于提供反馈的适当邮件列表。随着时间的推移,为新功能收集的反馈和经验有助于重塑和改进它们。一旦给定功能达到预期的稳定性和质量水平,它就可以利用常规机制,例如带有或不带有反馈机制的 JEP,最终目标是成为 Java 平台的永久功能。

更多学习

上次更新: 2023 年 12 月 1 日


返回教程列表