Java 16 - 快速指南


Java 16 - 概述

Java 16 是一个主要功能版本,它为 JAVA 带来了许多 JVM 特定的更改和语言特定的更改。它遵循 Java 发布节奏,从 Java 10 开始引入,并于 2021 年 3 月发布,距 Java 15 发布仅六个月。

Java 16 是非 LTS 版本。

新功能

以下是 Java 16 中引入的主要新功能。

  • JEP 338 - Vector API(孵化器) - 引入了新的 Vector API,允许开发人员显式执行向量操作。

  • JEP 347 - 启用 C++14 语言功能- C++ 14 功能可以在 JDK 16 的 C++ 源代码中使用。

  • JEP 357、JEP 369 - 从 Mercurial 迁移到 Git/GitHub - OpenJDK 源代码从 Mercurial 迁移到 Git/GitHub

  • JEP 376 - ZGC - 并发线程堆栈处理- Z 垃圾收集器通过将其线程堆栈处理从安全点转移到并发阶段而得到改进。

  • JEP 380 - Unix 域套接字通道- SocketChannel 和 ServerSocketChannel 现在支持 Unix 域套接字。

  • JEP 386 - Alpine Linux 端口- 现在 JDK 可用于 Alpine Linux 和其他使用 musl 实现的 Linux 发行版。

  • JEP 387 - 弹性元空间- 通过将未使用的 HotSpot 类元数据或元空间内存快速返回到操作系统来改进元空间内存管理,减少元空间占用空间并简化元空间代码。

  • JEP 388 - Windows/AArch64 端口- 现在 JDK 可以在 AArch64、ARM 硬件服务器或基于 ARM 的笔记本电脑上运行。

  • JEP 389 - 外部链接器 API(孵化器) - Java 代码可以由 C/C++ 调用,反之亦然,使用新的 API 替换 JNI。

  • JEP 390 - 基于值的类的警告- 如果使用 Synchronize 同步基于值的类,则会引发警告。

  • JEP 392 - 打包工具- jpackage 现在是标准而不是孵化器功能。

  • JEP 393 - 外部内存访问 API(第三个孵化器) - 外部内存访问 API 的小幅增强。

  • JEP 394 - instanceof 的模式匹配- instanceOf 的模式匹配现在是一个标准功能。

  • JEP 395 - 记录- 记录现在是一个标准功能。

  • JEP 396 - 默认情况下强烈封装 JDK 内部- --illegal-access 选项的默认模式现在为拒绝。早些时候是允许的。

  • JEP 397 - 密封类(第二预览版) - 对密封类的小幅增强。

Java 16 通过新方法和选项增强了众多 API。我们将在接下来的章节中看到这些变化。

Java 16 - 环境设置

在线现场演示选项

我们已经在线设置了Java编程环境,以便您可以在线编译和执行所有可用的示例。它使您对所阅读的内容充满信心,并使您能够使用不同的选项验证程序。请随意修改任何示例并在线执行。

使用以下示例代码框右上角的“实时演示”选项尝试以下示例 -

例子

public class MyFirstJavaProgram {
   public static void main(String []args) {
      System.out.println("Hello World");
   }
}

输出

Hello World

对于本教程中给出的大多数示例,您将在我们网站右上角的代码部分中找到“实时演示”选项,该选项将带您进入在线编译器。因此,请充分利用它并享受学习的乐趣。

本地环境设置

如果您想设置自己的 Java 编程语言环境,那么本节将指导您完成整个过程。请按照以下步骤设置您的 Java 环境。

Java SE 可供免费下载。要下载,请单击此处,请下载与您的操作系统兼容的版本。

按照说明下载 Java,然后运行​​.exe以在您的计算机上安装 Java。在计算机上安装 Java 后,您需要设置环境变量以指向正确的安装目录。

设置 Windows 2000/XP 的路径

假设您已将 Java 安装在 c:\Program Files\java\jdk 目录中 -

  • 右键单击“我的电脑”并选择“属性”。

  • 单击“高级”选项卡下的“环境变量”按钮。

  • 现在,编辑“Path”变量并在其末尾添加 Java 可执行文件目录的路径。例如,如果路径当前设置为C:\Windows\System32,则按以下方式编辑它

    C:\Windows\System32;c:\Program Files\java\jdk\bin

设置Windows 95/98/ME的路径

假设您已将 Java 安装在 c:\Program Files\java\jdk 目录中 -

  • 编辑“C:\autoexec.bat”文件并在末尾添加以下行 -

    设置路径=%PATH%;C:\Program Files\java\jdk\bin

设置 Linux、UNIX、Solaris、FreeBSD 的路径

应将环境变量 PATH 设置为指向 Java 二进制文件的安装位置。如果您在执行此操作时遇到问题,请参阅您的 shell 文档。

例如,如果您使用 bash 作为 shell,那么您可以在.bashrc末尾添加以下行-

  • 导出 PATH=/path/to/java:$PATH'

流行的 Java 编辑器

要编写 Java 程序,您需要一个文本编辑器。市场上还有更复杂的 IDE。最流行的简要描述如下 -

  • 记事本- 在 Windows 计算机上,您可以使用任何简单的文本编辑器,例如记事本(本教程推荐)或写字板。Notepad++ 也是一个免费的文本编辑器,增强了功能。

  • Netbeans - 它是一个开源且免费的 Java IDE,可以从www.netbeans.org/index.html下载。

  • Eclipse - 它也是由 Eclipse 开源社区开发的 Java IDE,可以从www.eclipse.org/下载。

IDE或集成开发环境,提供所有常见的工具和设施来帮助编程,例如源代码编辑器、构建工具和调试器等。

Java 16 - 密封类

Java 15 引入了密封类作为预览功能,它提供了对继承的细粒度控制。Java 16 提供了一些小的增强功能,并将此功能保留为预览版。以下是密封类需要考虑的要点 -

  • 密封类是使用 seal 关键字声明的。

  • 密封类允许使用 Permits 关键字声明哪个类可以是子类型。

  • 扩展密封类的类必须声明为密封类、非密封类或最终类。

  • 密封类有助于在继承中创建有限且可确定的类层次结构。

例子

考虑以下示例 -

ApiTester.java

public class APITester {
   public static void main(String[] args) {
      Person manager = new Manager(23, "Robert");
      manager.name = "Robert";
      System.out.println(getId(manager));
   }
   public static int getId(Person person) {
      if (person instanceof Employee) {
         return ((Employee) person).getEmployeeId();
      } 
      else if (person instanceof Manager) {
         return ((Manager) person).getManagerId();
      }
      return -1;
   }
}
abstract sealed class Person permits Employee, Manager {
   String name;
   String getName() {
      return name;
   }
}
final class Employee extends Person {
   String name;
   int id;
   Employee(int id, String name){
      this.id = id;
      this.name = name;
   }
   int getEmployeeId() {
      return id;
   }
}
non-sealed class Manager extends Person {
   int id;
   Manager(int id, String name){
      this.id = id;
      this.name = name;
   }
   int getManagerId() {
      return id;
   }
}

编译并运行程序

$javac -Xlint:preview --enable-preview -source 16 APITester.java
$java --enable-preview APITester

输出

23

Java 16 - instanceof 的模式匹配

Java 14 引入了instanceof 运算符来拥有类型测试模式作为预览功能。类型测试模式有一个谓词来指定具有单个绑定变量的类型。它仍然是 Java 15 中的预览功能。在 Java 16 中,此功能现已成为标准交付的一部分。

句法

if (person instanceof Employee e) {
   return e.getEmployeeId();
}

例子

考虑以下示例:

ApiTester.java

public class APITester {
   public static void main(String[] args) {
      Person manager = new Manager(23, "Robert");
      manager.name = "Robert";
      System.out.println(getId(manager));
   }
   public static int getId(Person person) {
      if (person instanceof Employee e) {
         return e.getEmployeeId();
      } 
      else if (person instanceof Manager m) {
         return m.getManagerId();
      }
      return -1;
   }
}
abstract class Person {
   String name;
   String getName() {
      return name;
   }
}
final class Employee extends Person {
   String name;
   int id;
   Employee(int id, String name){
      this.id = id;
      this.name = name;
   }
   int getEmployeeId() {
      return id;
   }
}
final class Manager extends Person {
   int id;
   Manager(int id, String name){
      this.id = id;
      this.name = name;
   }
   int getManagerId() {
      return id;
   }
}

编译并运行程序

$javac APITester.java
$java APITester

输出

23

Java 16 - 基于值的类的警告

某些类(例如 java.util.Optional 和 java.time.LocalDateTime)是基于值的。基于值的类的此类实例是最终的且不可变的。此类类具有注释@jdk.internal.ValueBased,并且 Java 16 现在会在此类类使用synchronized 关键字同步时生成编译时警告。包装类是基于值的。例如,Double 类是基于值的。

例子

package java.lang;
@jdk.internal.ValueBased
public final class Double extends Number
   implements Comparable<Double>, Constable, ConstantDesc {
   //...
}

考虑以下示例:

ApiTester.java

例子

public class APITester {
   public static void main(String[] args) {
      Double d = 10.0;
      synchronized (d) {
         System.out.println(d);			
      } 
   }
}

编译并运行程序

$javac APITester.java

输出

APITester.java:4: warning: [synchronization] attempt to synchronize on an instance of a value-based class
   synchronized (d) {
   ^
1 warning

Java 16 - 记录

Java 14 引入了新的类类型记录作为预览功能,以方便创建不可变数据对象。Java 15 进一步增强了记录类型。在 Java 16 中,记录现在已成为 JDK 的标准功能。

考虑以下示例 -

ApiTester.java

例子

public class APITester {
   public static void main(String[] args) {
      StudentRecord student = new StudentRecord (1, "Julie", "Red", "VI", 12);
      System.out.println(student.id());
      System.out.println(student.name());
      System.out.println(student);
   } 
}
record StudentRecord(int id, 
   String name, 
   String section, 
   String className,
   int age){}

编译并运行程序

$javac APITester.java
$java APITester

输出

1
Julie
StudentRecord[id=1, name=Julie, section=Red, className=VI, age=12]

Java 16 - 打包工具

Java 14引入了一个新的打包工具,基于javapackager的jpackage。javapackager 是在 Java 8 中引入的,是 JavaFX 工具包的一部分。由于 JavaFX 从 Java 11 版本中分离出来,因此标准产品中不再提供此打包工具。

这个新工具的开发目的是为操作系统提供本机安装程序。例如,用于 Windows 的 msi/exe、用于 MacOS 的 pkg/dmg、用于 Linux 的 deb/rpm 等等。如果没有这个工具,开发人员通常会共享一个 jar 文件,用户必须在自己的 JVM 中运行该文件。

开发人员可以使用jlink将所需的JDK模块压缩为最小模块,并使用jpackage创建轻量级映像。

考虑以下示例 -

API测试器.java

例子

public class APITester {
   public static void main(String[] args) {
      System.out.println("Welcome to TutorialsPoint.");
   }   
}

编译并运行程序

$javac APITester.java
$jar cf APITester.jar APITester.class

输出

对于 Windows 可执行文件,您需要下载WiX Toolset v3.11.2(wix311-binaries.zip)并将工具包添加到您的路径。

创建 jar 并设置路径后,将 jar 放入名为 lib 的文件夹中,并运行以下命令来创建 Windows MSI 安装程序。

$jpackage --input lib --name APITester --main-jar APITester.jar --main-class APITester --type msi

Java 16 - 垃圾收集器

Java 15 使 ZGC(Z 垃圾收集器)成为标准功能。在 Java 15 之前,这是一个实验性功能。它是低延迟、高度可扩展的垃圾收集器。

ZGC 在 Java 11 中作为实验性功能引入,因为开发者社区认为它太大而无法提前发布。

ZGC 具有高性能,即使在机器学习应用等海量数据应用中也能高效工作。它确保处理数据时不会因垃圾收集而长时间暂停。它支持 Linux、Windows 和 MacOS。

在Java 16中,ZGC线程堆栈处理从安全点转移到并发阶段,并大大提高了效率。以下是所做的增强。

  • 线程堆栈处理已从 ZGC 安全点移出。

  • 堆栈处理变得惰性、协作、并发和增量。

  • 所有其他每线程根处理都将从 ZGC 安全点中删除。

  • HotSpot 子系统可以延迟处理堆栈。

Java 16 - 其他增强功能

JEP 338 - 矢量 API(孵化器)

JIT编译器通过自动将一些标量运算(一次一项)转换为向量运算(一次多项)来优化算术算法。但开发人员无法控制这个过程。甚至不是所有的标量运算都可以转换为向量运算。在此 JEP 中,引入了新的 VECTOR API,允许开发人员显式执行 Vector 操作。

它是一个孵化器模块 jdk.incubator.vector,用于表达向量计算,以便在运行时可靠地编译为最佳向量硬件指令。

JEP 347 - 启用 C++14 语言功能

直到 JDK 15,JDK 支持 C++98/03 语言标准。通过 JEP 347,Java 现在正式允许 JDK 内的 C++ 源代码更改以使用 C++14 语言功能,并提供有关哪些功能可以在 HotSpot 代码中使用的具体指导。

JEP 357/369 - 从 Mercurial 迁移到 GitHub

在 JEP 357/369 中,OpenJDK 源代码已从 Mercurial 移至 Git/GitHub。以下是这一运动的主要因素。

  • 版本控制系统元数据的大文件大小 (Mercurial)

  • 可用工具

  • 可用托管

JEP 380 - Unix 域套接字通道

Unix 域套接字用于同一主机上的进程间通信 (IPC),以在进程之间交换数据。这些套接字与 TCP/IP 套接字类似,只是通过文件系统路径名而不是 Internet 协议 (IP) 地址和端口号来寻址。大多数 Unix 平台(Windows 10 和 Windows Server 2019)都支持 Unix 域套接字。JEP 380 向 SocketChannel 和 ServerSocketChannel 添加了 Unix 域套接字支持。

Java 16 - 弃用和删除

弃用

  • ThreadGroup 方法(例如 stop、destroy、isDestroyed、setDaemon 和 isDaemon 方法)已弃用,并将在未来版本中删除。这些销毁线程组的 API/机制是有缺陷的,并且这种支持显式或自动销毁线程组的方法最终被弃用。

  • 信号链 API(如 sigset、signal)已过时,并且已弃用。sigaction 是跨平台的,并且是多线程进程支持的 API。

  • 不推荐使用将 DN 表示为主体或字符串对象的 java.security.cert API。

  • 已过时或未使用 SunEC 提供商的现代公式和技术实现的椭圆曲线已被删除。

搬迁

  • 非公共类 java.awt.PeerFixer 已被删除。其目的是为 JDK 1.1.1 之前创建的 ScrollPane 对象提供反序列化支持。

  • jaotc,一个实验性的 Java 提前编译工具被删除。基于 Java 的实验性 JIT 编译器 Graal 也被删除。

  • 具有弱 1024 位 RSA 公钥的根证书已从 cacerts 密钥库中删除。