JDK9新特性概括 - 极悦
首页 课程 师资 教程 报名

JDK9新特性概括

  • 2022-10-14 09:58:02
  • 1076次 极悦

1.概述

Java 9 带有丰富的特性集。虽然没有新的语言概念,但新的 API 和诊断命令肯定会引起开发人员的兴趣。

在这篇文章中,我们将对一些新功能进行快速、高级的了解;此处提供了新功能的完整列表。

2.模块化系统——拼图项目

让我们从最重要的开始——将模块化引入 Java 平台。

模块化系统提供类似于 OSGi 框架系统的功能。模块具有依赖关系的概念,可以导出公共 API 并将实现细节隐藏/私有。

这里的主要动机之一是提供模块化 JVM,它可以在可用内存少得多的设备上运行。JVM 只能使用应用程序所需的那些模块和 API 运行。查看此链接以了解这些模块是什么。

此外,无法再从应用程序代码访问com.sun.*等 JVM 内部(实现)API 。

简而言之,这些模块将在位于 java 代码层次结构顶部的名为module-info.java的文件中进行描述:

module com.baeldung.java9.modules.car {
    requires com.baeldung.java9.modules.engines;
    exports com.baeldung.java9.modules.car.handling;
}

我们的模块车需要模块引擎来运行并导出一个包进行处理。

3. 一个新的 HTTP 客户端

期待已久的旧HttpURLConnection替代品。

新 API 位于java.net.http包下。

它应该支持HTTP/2 协议和WebSocket握手,其性能应该可以与Apache HttpClient、Netty和Jetty相媲美。

让我们通过创建和发送一个简单的 HTTP 请求来看看这个新功能。

更新:HTTP 客户端 JEP正在移至 Incubator 模块,因此它不再在包java.net.http中可用,而是在jdk.incubator.http 下可用。

快速获取请求

API 使用 Builder 模式,这使得快速使用变得非常容易:

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("http://postman-echo.com/get"))
  .GET()
  .build();
HttpResponse<String> response = HttpClient.newHttpClient()
  .send(request, HttpResponse.BodyHandler.asString());

4.流程API

进程 API 已针对控制和管理操作系统进程进行了改进。

(1)处理信息

java.lang.ProcessHandle类包含大部分新功能:

ProcessHandle self = ProcessHandle.current();
long PID = self.getPid();
ProcessHandle.Info procInfo = self.info();
Optional<String[]> args = procInfo.arguments();
Optional<String> cmd =  procInfo.commandLine();
Optional<Instant> startTime = procInfo.startInstant();
Optional<Duration> cpuUsage = procInfo.totalCpuDuration();

current方法返回一个对象,表示当前正在运行的 JVM 的进程。Info子类提供有关该过程的详细信息。

(2)销毁进程

现在 - 让我们使用destroy()停止所有正在运行的子进程:

childProc = ProcessHandle.current().children();
childProc.forEach(procHandle -> {
    assertTrue("Could not kill process " + procHandle.getPid(), procHandle.destroy());
});

5.小语言修改

(1)试用资源

在 Java 7 中,try-with-resources语法要求为语句管理的每个资源声明一个新变量。

在 Java 9 中还有一个额外的改进:如果资源被 final 或有效的 final 变量引用,则 try-with-resources 语句可以在不声明新变量的情况下管理资源:

MyAutoCloseable mac = new MyAutoCloseable();
try (mac) {
    // do some stuff with mac
}
try (new MyAutoCloseable() { }.finalWrapper.finalCloseable) {
   // do some stuff with finalCloseable
} catch (Exception ex) { }

(2)钻石运算符扩展

现在我们可以将菱形运算符与匿名内部类结合使用:

FooClass<Integer> fc = new FooClass<>(1) { // anonymous inner class
};
FooClass<? extends Integer> fc0 = new FooClass<>(1) { 
    // anonymous inner class
};
FooClass<?> fc1 = new FooClass<>(1) { // anonymous inner class
};

(3)接口私有方法

即将发布的 JVM 版本中的接口可以具有私有方法,可用于拆分冗长的默认方法:

interface InterfaceWithPrivateMethods {    
    private static String staticPrivate() {
        return "static private";
    }    
    private String instancePrivate() {
        return "instance private";
    }    
    default void check() {
        String result = staticPrivate();
        InterfaceWithPrivateMethods pvt = new InterfaceWithPrivateMethods() {
            // anonymous class
        };
        result = pvt.instancePrivate();
    }
}}

6. JShell 命令行工具

JShell 是 read-eval-print 循环——简称 REPL。

简而言之,它是一个交互式工具,用于评估 Java 的声明、语句和表达式,以及一个 API。测试小代码片段非常方便,否则需要使用main方法创建一个新类。

jshell可执行文件本身可以在<JAVA_HOME>/bin文件夹中找到:

jdk-9\bin>jshell.exe
|  Welcome to JShell -- Version 9
|  For an introduction type: /help intro
jshell> "This is my long string. I want a part of it".substring(8,19);
$5 ==> "my long string"

交互式外壳带有历史记录和自动完成功能;它还提供诸如保存和加载文件、所有或部分书面语句的功能:

jshell> /save c:\develop\JShell_hello_world.txt
jshell> /open c:\develop\JShell_hello_world.txt
Hello JShell!

代码片段在文件加载时执行。

7. JCMD 子命令

让我们探索jcmd命令行实用程序中的一些新子命令。我们将获得 JVM 中加载的所有类及其继承结构的列表。

在下面的示例中,我们可以看到运行 Eclipse Neon 的 JVM 中加载的java.lang.Socket的层次结构:

jdk-9\bin>jcmd 14056 VM.class_hierarchy -i -s java.net.Socket
14056:
java.lang.Object/null
|--java.net.Socket/null
|  implements java.io.Closeable/null (declared intf)
|  implements java.lang.AutoCloseable/null (inherited intf)
|  |--org.eclipse.ecf.internal.provider.filetransfer.httpclient4.CloseMonitoringSocket
|  |  implements java.lang.AutoCloseable/null (inherited intf)
|  |  implements java.io.Closeable/null (inherited intf)
|  |--javax.net.ssl.SSLSocket/null
|  |  implements java.lang.AutoCloseable/null (inherited intf)
|  |  implements java.io.Closeable/null (inherited intf)

jcmd命令的第一个参数是我们要在其上运行命令的 JVM 的进程 ID (PID)。

另一个有趣的子命令是set_vmflag。我们可以在线修改一些JVM参数,而不需要重启JVM进程和修改它的启动参数。

您可以使用子命令jcmd 14056 VM.flags -all找出所有可用的 VM 标志

8. 多分辨率图像API

接口java.awt.image.MultiResolutionImage将一组具有不同分辨率的图像封装到一个对象中。我们可以根据给定的 DPI 指标和图像转换集检索特定于分辨率的图像变体,或者检索图像中的所有变体。

java.awt.Graphics类根据当前显示 DPI 指标和任何应用的转换从多分辨率图像中获取变体。

java.awt.image.BaseMultiResolutionImage类提供了基本实现:

BufferedImage[] resolutionVariants = ....
MultiResolutionImage bmrImage
  = new BaseMultiResolutionImage(baseIndex, resolutionVariants);
Image testRVImage = bmrImage.getResolutionVariant(16, 16);
assertSame("Images should be the same", testRVImage, resolutionVariants[3]);

9.可变手柄

API 位于java.lang.invoke下,由VarHandle和MethodHandles组成。它在对象字段和数组元素上提供等效的java.util.concurrent.atomic和sun.misc.Unsafe操作,具有相似的性能。

使用 Java 9 Modular 系统将无法从应用程序代码访问sun.misc.Unsafe 。

10. 发布-订阅框架

java.util.concurrent.Flow类提供了支持Reactive Streams发布-订阅框架的接口。这些接口支持跨在 JVM 上运行的多个异步系统的互操作性。

我们可以使用实用程序类SubmissionPublisher来创建自定义组件。

11. 统一的 JVM 日志记录

此功能为 JVM 的所有组件引入了一个通用的日志记录系统。它提供了进行日志记录的基础设施,但它没有添加来自所有 JVM 组件的实际日志记录调用。它也不向 JDK 中的 Java 代码添加日志记录。

日志框架定义了一组标签——例如gc、编译器、线程等。我们可以使用命令行参数-Xlog在启动期间打开日志。

让我们使用'debug'级别将带有'gc'标签的消息记录到一个名为'gc.txt'的文件中,没有任何修饰:

java -Xlog:gc=debug:file=gc.txt:none ...

-Xlog:help将输出可能的选项和示例。可以使用jcmd命令在运行时修改日志记录配置。我们将设置 GC 日志为 info 并将它们重定向到一个文件 - gc_logs:

jcmd 9615 VM.log output=gc_logs what=gc

12. 新的 API

(1)不可变集

java.util.Set.of() – 创建给定元素的不可变集合。在 Java 8 中,创建一个由多个元素组成的 Set 需要几行代码。现在我们可以简单地做到这一点:

Set<String> strKeySet = Set.of("key1", "key2", "key3");

(2)可选择流式传输

java.util.Optional.stream()为我们提供了一种在 Optional 元素上使用 Streams 功能的简单方法:

List<String> filteredList = listOfOptionals.stream()
  .flatMap(Optional::stream)
  .collect(Collectors.toList());

 

选你想看

你适合学Java吗?4大专业测评方法

代码逻辑 吸收能力 技术学习能力 综合素质

先测评确定适合在学习

在线申请免费测试名额
价值1998元实验班免费学
姓名
手机
提交