Java 17有什么新特性?

Java 17的长期支持(LTS)版本于2021年9月14日发布。让我们了解一下Java 17的新功能以及是否应该升级。

许多应用程序使用旧版本的Java,包括早期的Java LTS版本:Java 11和Java 8。

为什么企业应该升级到最新的Java版本?升级到Java 17需要努力,主要是为了充分利用JVM内部的新功能和功能。

许多企业使用Docker和Docker images,以最小的工作量和时间轻松切换到Java 17。开发人员可以定义其持续集成/部署(CI/CD)流水线,并在Docker镜像中运行所有内容。这不会影响使用旧版Java的其他团队,因为他们可以使用旧的Docker镜像。

JAVA 17功能

macOS和AArch64支持

此版本添加的关键JVM功能之一是使用JEP 391增强了对AArch64架构上macOS的支持。它将支持Apple在去年推出的最新一系列处理器(M1)。

对于这些平台上的用户来说,这并不一定是一件大事,因为一些供应商已经发布了支持此架构的JDK版本,甚至可以返回从Java 8开始的支持。然而,官方认可是确保未来维护和支持平台的重要因素。相比之下,Java 9添加了对Linux/AArch64平台的支持,Java 16添加了对Windows/AArch64的支持。

封闭类

封闭类是Java 17引入的一项功能。封闭类功能已经完成试用阶段,并在Java 17中成为官方平台和语言。它允许开发人员指定类型可以具有的可允许的子类型,并防止其他类型以不打算的方式进行扩展或实现。

封闭类还允许编译器在编译时生成错误,当您尝试将未封闭类型转换为非允许的子类型时。Java 17还为在macOS上运行使用Apple Metal API而不是OpenGL的AWT/Swing应用程序带来了新的渲染管道。它具有改进的API和增强的随机数生成功能。

Java 17中的更改、删除和限制

Java 17还带来了一些更改、删除和新的限制。

JDK内部的封装

一个变化是JDK内部封装过程的结束。这是在Java 9中首次引入的,当用户尝试使用反射或类似的方法规避对使用内部APIs的常规限制时,会在运行时发出警告。还添加了命令行参数来规范此行为。

从Java 9开始,已经创建了各种API来提供一种统一的方式来执行最常用的任务;用户将在内部使用这些API。在Java 16中,将默认值从警告更改为禁用访问并抛出异常。但是,它使用命令行参数来改变行为。

在Java 17中,删除了命令行参数,并且可以取消激活此限制。这意味着对这些内部API的所有非授权访问现在都受到保护。

始终严格的浮点语义

另一种“去除”可以被描述为重新引入Always-Strict浮点语义。Java 1.2引入了对Java中浮点语义默认的修改,允许JVM在浮点计算中在精度方面进行微小的牺牲以提高性能。在需要使用严格语义的类和方法中,添加了一个strictfp关键字。自那时以来,各种指令集类型已被引入到CPU中,使得严格浮点语义可以无需额外成本地使用。实现默认或严格语义的需求已被消除。

Java 17去除了先前的默认语义,所有浮点操作都将被严格执行。术语strictfp仍然存在。然而,它没有任何效果,并且在时间compile上会引发警告。

提前编译(AOT)

Java 9引入了提前编译(AOT)作为一个实验性功能,利用Graal编译器,并使用Java编写了JIT代码。Java 10通过整合JVMCI接口使Graal编译器可以在OpenJDK中作为JIT编译器使用。自发布以来,它取得了巨大的改进。Graal编译器在GraalVM的名称下拥有自己的JVM。

RMI激活

RMI激活在Java 8中被删除后,在Java 15中被最终弃用并标记为需移除的要求。RMI激活提供了一种使用RMI在需求时启用分布式对象的方法。然而,它的使用非常有限,而且现在有更好的替代方案。激活部分的消除不会影响RMI的其余部分。

Applet API的移除

Applet API最终在Java 9中被指定为移除的对象。Applet API提供了一种将Java AWT/Swing控件集成到浏览器中的方法。然而,现代浏览器无法支持这一点,这意味着在过去的十年左右,Applets基本上无法访问。

安全管理器

最重要的弃用是安全管理器(JEP 411)。安全管理器自Java 1.0以来一直在使用。它旨在限制Java在本地机器上的操作,例如限制对网络、文件和其他网络资源的访问。它还试图通过阻止反射和特定API来隔离不受信任的代码。

安全管理器的终结始于Java 12。添加了一个命令行参数以在运行时阻止使用安全管理器。Java 17中的改变意味着在尝试设置安全管理器时,无论是从命令行还是在运行时动态设置,JVM都将生成一个运行时警告。

孵化器和预览功能

许多人想知道Java 17是否具有任何预览和孵化器功能,考虑到Java 17被宣称为长期支持版本。Java 17有两个孵化器模块和一个预览功能!

Vector API

Vector API(JEP 414)目前处于孵化器的第二阶段。该API允许开发人员定义矢量计算,JIT编译器将其转换为JVM所运行的CPU架构支持的适当矢量指令(例如,使用SSE或AVX指令集)。

以前,开发人员必须使用标量函数或构建特定于平台的本机库。在Java中实现Vector API还提供了一种无缝回退机制,在早期版本中这是很复杂的。

Vector API的标准化使得JDK中的类可以使用它。Java Arrays mismatch()方法可以改为在Java上运行,从而消除了在JVM内部维护和编写多个特定于平台的实现的要求。

Foreign Function & Memory API

另一个孵化器功能是称为Foreign Function & Memory API(JEP 412)。它是Java 16的另外两个孵化器模块Foreign Linker API(JEP 389)和Foreign-Memory API(JEP 393)的进化和合并。它们都通过使用在Java中编写的静态类型编程来提供对本机内存和代码的访问。

用于Switch的模式匹配

Java 17中包含的语言预览的最后一个功能是Pattern Matching for Switch(JEP 406)。这个语言特性根据类型扩展了switch表达式和语句,类似于Java 16中使用的Pattern Matching(JEP 394)的语法,它已成为标准。

过去,如果您想根据对象的动态特性执行不同的操作,您需要使用if-else链构建一个包含实例检查的检查,例如:

String type(Object o) {
  if (o instanceof List) {
    return "A List of things.";
  }
  else if (o instanceof Map) {
    return "A Map! It has keys and values.";
  }
  else if (o instanceof String) {
    return "This is a string.";
  }
  else {
    return "This is something else.";
  }
}

通过将switch表达式与switch的新模式匹配功能相结合,该过程可以简化为类似以下内容:

String type(Object o) {
  return switch (o) {
    case List l -> "A List of things.";
    case Map m -> "A Map! It has keys and values.";
    case String s -> "This is a string.";
    default -> "This is something else.";
  };
}

您可能已经注意到,在检查过程中有一个变量的声明。与Pattern中的其他变量一样,实例匹配表示该对象已进行类型检查和转换,并可从当前范围内的变量中访问。

预览功能是向模式匹配迈进的另一步。下一步是包括解构数组和记录的能力。

是否应升级到Java 17?

是的,您必须不断升级到最新版本,但不要在第一天就升级。您正在使用的软件和库可能尚未更新以支持Java 17的兼容性,因此您可能需要等待一段时间。

如果您被困在像Java 8或Java 11这样的LTS版本中,语言内部和JVM内部都有许多选项需要升级到Java 17。由于它是一个长期维护版本,您的生产环境最终可能也会升级到Java 17。

如果您开始一个全新的项目,或者正在准备您的项目并为Java 17做好准备,尽早切换到Java 17可能是最有效的选择,因为它减少了移动的成本。这也使得参与项目开发的开发人员可以利用所有最新的功能和运营方面。

您可以利用过去几年中发生的许多改进,例如对运行Java的容器的改进支持,以及新的低延迟垃圾收集器实现。

类似文章