Java 17新特性


Java 17计划于 9 月 14日发布,来自不同供应商的版本将在当天或之后发布。Java 17 的特别之处当然是 Oracle 和 OpenJDK 社区都决定这将是一个长期支持版本,就像 Java 11 和之前的 Java 8 一样。
自从从 Java 10 开始引入快速发布节奏以来,除 Oracle 之外的许多供应商都加紧生产具有各种级别支持的生产就绪二进制文件,包括AmazonAzulBellSoftMicrosoftSAPEclipse Adoptium(以前为AdoptOpenJDK)。
 
下面是新的特性:

  • macOS 上的 AArch64 支持

此版本中添加的突出功能之一是支持AArch64上的macOS ,增加了Apple 去年发布的新 CPU 系列 (M1) 的支持。对于在这些平台上运行的人来说,这并不是什么新闻,因为一些供应商已经发布了支持这种架构的 JDK 版本,甚至将支持一直回溯到 Java 8。 尽管如此,官方批准版本仍然很重要平台未来的维护和支持。为了比较,Java 9 中添加了对 Linux/AArch64 平台的支持,Java 16 中添加了对 Windows/AArch64 的支持。
  • 密封类

Sealed Classes 特性已完成其预览阶段,现在是 Java 17 中语言和平台的标准部分,如JEP 409 中所定义。密封类允许开发人员显式声明类型的允许子类型,从而防止其他人无意中扩展或实现它。
  • 其他新功能

Java 17 还为在 macOS 上运行的 AWT/Swing 应用程序带来了新的渲染管道 ( JEP 382 ),使用 Apple 的 Metal API 而不是 OpenGL,以及用于生成随机数的新 API 和增强功能 ( JEP 356 )。
  
其他限制或弃用功能:
  • JDK内部元素强封装

JEP 403强封装 JDK 的所有内部元素,除了 关键的内部 API,如sun.misc.Unsafe. 不再可能通过单个命令行选项访问。将 JDK 从默认的宽松强封装转换为默认 强封装。
在Java9中,如果用户尝试使用反射或喜欢绕过使用其他内部 API 的正常限制,则会发出运行时警告。还添加了命令行参数来控制此行为。在 Java 16 中,默认设置从发出警告更改为通过抛出异常拒绝访问,但仍保留命令行参数以更改行为。
现在在 Java 17 中,进一步删除了这些命令行参数,当然也能禁用此限制,这意味着对这些内部 API 的所有未经授权的访问现在都被强封装。
好处:
  1. 继续提高 JDK 的安全性和可维护性
  2. 鼓励开发人员从使用内部元素迁移到使用标准 API,以便他们和他们的用户可以轻松升级到未来的 Java 版本。

 
  • 始终严格的浮点语义

恢复 Always-Strict Floating-Point Semantics ( JEP 306 )。Java 1.2 引入了对 Java 中默认浮点语义的更改,实质上允许 JVM 以牺牲一点点浮点精度来换取性能。对于需要应用严格语义的方法和类,引入了一个关键字strictfp。从那时起,新的指令集被添加到 CPU 中,导致在没有过度开销的情况下操作严格的浮点语义,因此不再有默认和严格语义的动机。
Java 17 删除了以前的默认语义,所有浮点运算现在都严格执行。该关键字strictfp仍然存在,但没有效果并产生编译时警告。
 
  • 删除实验性 AOT 和 JIT 编译器

删除实验性的基于 Java 的提前 (AOT) 和即时 (JIT) 编译器。该编译器自推出以来几乎没有什么用处,维护它所需的工作量很大。
Java 9 引入了提前 (AOT) 编译作为使用 Graal 编译器(一种用 Java 编写的 JIT 编译器)的实验性功能。Java 10 使用添加的 JVMCI 接口使 Graal 编译器可用作 OpenJDK 中的 JIT 编译器。
JEP 410 中,AOT 和 JIT 编译器已被删除。
  • 删除RMI 激活

RMI Activation 在JEP 407 中被删除,在 Java 8 中成为可选的,最终在 Java 15 中被弃用并标记为删除。 RMI Activation 启用了一种通过 RMI 激活分布式对象按需资源的方法,但几乎没有用,并且今天存在更好的替代方案。RMI 的其余部分不受激活部分的影响。
  • 删除Applet API

Applet API 终于在JEP 398 中被标记为删除,它之前在 Java 9 中被弃用。 Applet API 提供了一种将 Java AWT/Swing 控件嵌入到浏览器网页中的方法,但今天没有现代浏览器支持这一点,所以在过去十年或更长时间里,Applet 基本上是无关紧要的。
  • 弃用安全管理器

毫无疑问,最大的弃用是安全管理器(JEP 411)。安全管理器自 Java 1.0 以来一直存在,通常旨在限制 Java 可以在本地机器上执行的操作,例如限制对文件、网络等的访问,或通过禁止使用反射来尝试沙箱不可信代码,以及某些 API。
安全管理器的弃用始于 Java 12,其中添加了一个禁止使用它的命令行参数,从 Java 18 开始,该命令行参数将默认为禁止在运行时设置安全管理器。Java 17 中的更改意味着在尝试从命令行或在运行时动态设置安全管理器时,JVM 将产生运行时警告。
 
孵化器和预览功能
许多人想知道 Java 17 是否会有任何孵化器和预览功能,因为它被提升为一个长期支持的版本,并且可能支持一个改变或长时间没有被淘汰的功能似乎是不明智的。但是我们来了,Java 17 有两个孵化器模块和一个预览语言功能!
  • Vector API 

Vector API ( JEP 414 ) 正在经历其第二个孵化器阶段。该 API 使开发人员能够表达向量计算,然后 JIT 编译器可以将其编译为运行 JVM 的 CPU 架构所支持的适当向量指令(例如,利用 SSE 和 AVX 指令集)。
以前,开发人员要么必须依赖标量操作,要么必须使用/开发特定于平台的本机库。在 Java 中实现 Vector API 还可以为当前架构没有必要指令的事物提供优雅的回退,而是必须回退以以不同的方式计算。
虽然不是此 JEP 的一部分,但 Vector API 的标准化也使 JDK 中的类能够使用它。诸如 Arrays.mismatch 之类的方法,如今在某些平台上具有固有的矢量化实现,可以重写以使其全部在 Java 中运行,从而无需在 JVM 中编写和维护多个特定于平台的实现。
  • 外部函数和内存 API

另一个孵化器模块是外来函数和内存 API ( JEP 412 ),它在技术上是 Java 16 中两个先前孵化器模块的合并和演变:外来链接器 API ( JEP 389 ) 和外来内存访问 API ( JEP 393 )。这两个组合允许使用用 Java 编写的静态类型代码访问本机代码和内存的方法,目的是能够在这种情况下取​​代 JNI 的使用。
  • Switch模式匹配

Java 17 中的最后一个语言预览功能是包含用于 switch 的模式匹配 ( JEP 406 )。此语言功能扩展了 switch 表达式和语句,使其还能够基于类型进行 switch,类似于模式匹配引入的 instanceof ( JEP 394 )语法,该语法在 Java 16 中标准化。
以前,如果您想根据对象的动态类型执行不同的操作,您需要使用 instanceof 检查创建一个 if-else if 链,例如:
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.";
  };
}