New Features in Java 9 – Java 9的新功能

最后修改: 2016年 10月 11日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Java 9 comes with a rich feature set. Although there are no new language concepts, new APIs and diagnostic commands will definitely be interesting to developers.

Java 9带有丰富的功能集。虽然没有新的语言概念,但新的API和诊断命令肯定会让开发者感兴趣。

In this writeup we’re going to have quick, high level look at some of the new features; a full list of new features is available here.

在这篇报道中,我们将快速、高水平地了解一些新功能;新功能的完整列表可在这里获得。

2. Modular System – Jigsaw Project

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

Let’s start with the big one – bringing modularity into the Java platform.

让我们从大的方面开始–将模块化带入Java平台。

A modular system provides capabilities similar to OSGi framework’s system. Modules have a concept of dependencies, can export a public API and keep implementation details hidden/private.

模块系统提供了类似于OSGi框架系统的能力。模块有一个依赖关系的概念,可以输出一个公共的API,并保持实现细节的隐藏/私有化。

One of the main motivations here is to provide modular JVM, which can run on devices with a lot less available memory. The JVM could run with only those modules and APIs which are required by the application. Check out this link for a description of what these modules are.

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

Also, JVM internal (implementation) APIs like com.sun.* are no longer accessible from application code.

另外,JVM内部(实现)API,如com.sun.*,不再能从应用程序代码中访问。

Simply put, the modules are going to be described in a file called module-info.java located in the top of java code hierarchy:

简单地说,模块将被描述在一个叫做module-info.java的文件中,该文件位于java代码层次结构的顶端。

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

Our module car requires module engine to run and exports a package for handling.

我们的模块car需要模块engine来运行,并为handling输出一个包。

For more in-depth example check OpenJDK Project Jigsaw: Module System Quick-Start Guide.

关于更深入的例子,请查看OpenJDK Project Jigsaw:模块系统快速启动指南

3. A New HTTP Client

3.一个新的HTTP客户端

A long-awaited replacement of the old HttpURLConnection.

一个期待已久的旧HttpURLConnection的替代品。

The new API is located under the java.net.http package.

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

It should support both HTTP/2 protocol and WebSocket handshake, with performance that should be comparable with the Apache HttpClient, Netty and Jetty.

它应该同时支持HTTP/2协议WebSocket握手,其性能应该与Apache HttpClientNettyJetty相近。

Let have a look at this new functionality by creating and sending a simple HTTP request.

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

Update: The HTTP Client JEP is being moved to Incubator module, so it is no longer available in the package java.net.http and instead is available under jdk.incubator.http.

更新:HTTP 客户端 JEP正被转移到孵化器模块中,因此它不再在java.net.http包中提供,而是在jdk.incubator.http.中提供。

3.1. Quick GET Request

<3.1快速GET请求

The API uses the Builder pattern, which makes it really easy for quick use:

该API使用了生成器模式,这使得它真正易于快速使用。

HttpRequest request = HttpRequest.newBuilder()
  .uri(new URI("https://postman-echo.com/get"))
  .GET()
  .build();

HttpResponse<String> response = HttpClient.newHttpClient()
  .send(request, HttpResponse.BodyHandler.asString());

4. Process API

4.过程API

The process API has been improved for controlling and managing operating-system processes.

进程API已被改进,用于控制和管理操作系统的进程。

4.1. Process Information

4.1.过程信息

The class java.lang.ProcessHandle contains most of the new functionalities:

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();

The current method returns an object representing a process of currently running JVM. The Info subclass provides details about the process.

current方法返回一个对象,代表当前运行的JVM的一个进程。Info子类提供了关于该进程的详细信息。

4.2. Destroying Processes

4.2.破坏进程

Now – let’s stop all the running child processes using destroy():

现在–让我们使用destroy()停止所有运行中的子进程。

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

5. Small Language Modifications

5.小语言的修改

5.1. Try-With-Resources

5.1.尝试使用资源

In Java 7, the try-with-resources syntax requires a fresh variable to be declared for each resource being managed by the statement.

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

In Java 9 there is an additional refinement: if the resource is referenced by a final or effectively final variable, a try-with-resources statement can manage a resource without a new variable being declared:

在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) { }

5.2. Diamond Operator Extension

5.2.钻石操作员扩展

Now we can use diamond operator in conjunction with anonymous inner classes:

现在我们可以结合匿名内层类来使用钻石操作符。

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
};

5.3. Interface Private Method

5.3.接口私有方法

Interfaces in the upcoming JVM version can have private methods, which can be used to split lengthy default methods:

在即将到来的JVM版本中,接口可以有private方法,这可以用来分割冗长的默认方法。

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 Command Line Tool

6.JShell命令行工具

JShell is read–eval–print loop – REPL for short.

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

Simply put, it’s an interactive tool to evaluate declarations, statements, and expressions of Java, together with an API. It is very convenient for testing small code snippets, which otherwise require creating a new class with the main method.

简单地说,它是一个评估Java的声明、语句和表达式的互动工具,同时还有一个API。它对于测试小的代码片段非常方便,否则需要用main方法创建一个新类。

The jshell executable itself can be found in <JAVA_HOME>/bin folder:

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"

The interactive shell comes with history and auto-completion; it also provides functionality like saving to and loading from files, all or some of the written statements:

交互式shell带有历史记录和自动完成功能;它还提供了保存到文件和从文件加载的功能,以及所有或部分的书面语句。

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

Code snippets are executed upon file loading.

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

7. JCMD Sub-Commands

7.JCMD子命令

Let’s explore some of the new subcommands in jcmd command line utility. We will get a list of all classes loaded in the JVM and their inheritance structure.

让我们探索一下jcmd命令行工具中的一些新子命令。我们将得到一个在JVM中加载的所有类的列表以及它们的继承结构。

In the example below we can see the hierarchy of java.lang.Socket loaded in JVM running Eclipse Neon:

在下面的例子中,我们可以看到在运行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)

The first parameter of jcmd command is the process id (PID) of the JVM on which we want to run the command.

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

Another interesting subcommand is set_vmflag. We can modify some JVM parameters online, without the need of restarting the JVM process and modifying its startup parameters.

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

You can find out all the available VM flags with subcommand jcmd 14056 VM.flags -all

你可以通过子命令jcmd 14056 VM.flags -all找出所有可用的VM标志。

8. Мulti-Resolution Image API

8.Multi-Resolution Image API

The interface java.awt.image.MultiResolutionImage encapsulates a set of images with different resolutions into a single object. We can retrieve a resolution-specific image variant based on a given DPI metric and set of image transformations or retrieve all of the variants in the image.

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

The java.awt.Graphics class gets variant from a multi-resolution image based on the current display DPI metric and any applied transformations.

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

The class java.awt.image.BaseMultiResolutionImage provides basic implementation:

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. Variable Handles

9.可变手柄

The API resides under java.lang.invoke and consists of VarHandle and MethodHandles. It provides equivalents of java.util.concurrent.atomic and sun.misc.Unsafe operations upon object fields and array elements with similar performance.

该API位于java.lang.invoke下,由VarHandleMethodHandles组成。它提供了与java.util.concurrent.atomicsun.misc.Unsafe对对象字段和数组元素的操作相当的性能。

With Java 9 Modular system access to sun.misc.Unsafe will not be possible from application code.

随着Java 9模块化系统对sun.misc.Unsafe的访问将无法从应用程序代码中实现。

10. Publish-Subscribe Framework

10.发布-订阅框架

The class java.util.concurrent.Flow provides interfaces that support the Reactive Streams publish-subscribe framework. These interfaces support interoperability across a number of asynchronous systems running on JVMs.

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

We can use utility class SubmissionPublisher to create custom components.

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

11. Unified JVM Logging

11.统一JVM日志记录

This feature introduces a common logging system for all components of the JVM. It provides the infrastructure to do the logging, but it does not add the actual logging calls from all JVM components. It also does not add logging to Java code in the JDK.

该功能为JVM的所有组件引入了一个通用的日志系统。它提供了做日志的基础结构,但它并没有从所有JVM组件中添加实际的日志调用。它也没有为JDK中的Java代码添加日志。

The logging framework defines a set of tags – for example, gc, compiler, threads, etc. We can use the command line parameter -Xlog to turn on logging during startup.

日志框架定义了一组标记–例如,gccompilerthreads,等等。我们可以使用命令行参数-Xlog来打开启动期间的日志记录。

Let’s log messages tagged with ‘gc’ tag using ‘debug’ level to a file called ‘gc.txt’ with no decorations:

让我们使用’debug’级别将带有’gc’标签的信息记录到一个叫做’gc.txt’的文件中,没有任何装饰。

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

-Xlog:help will output possible options and examples. Logging configuration can be modified runtime using jcmd command. We are going to set GC logs to info and redirect them to a file – gc_logs:

-Xlog:help将输出可能的选项和例子。日志配置可以在运行时使用jcmd命令来修改。我们要将GC日志设置为信息,并将其重定向到一个文件–GC_logs。

jcmd 9615 VM.log output=gc_logs what=gc

12. New APIs

12.新的API

12.1. Immutable Set

12.1.不可变的集合

java.util.Set.of() – creates an immutable set of a given elements. In Java 8 creating a Set of several elements would require several lines of code. Now we can do it as simple as:

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

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

The Set returned by this method is JVM internal class: java.util.ImmutableCollections.SetN, which extends public java.util.AbstractSet. It is immutable – if we try to add or remove elements, an UnsupportedOperationException will be thrown.

这个方法返回的Set是JVM的内部类。java.util.ImmutableCollections.SetN,它扩展了公共java.util.AbstractSet。它是不可变的–如果我们试图添加或删除元素,将会抛出一个不支持操作的异常

You can also convert an entire array into a Set with the same method.

你也可以用同样的方法将整个数组转换成Set

12.2. Optional to Stream

12.2.可选的流媒体

java.util.Optional.stream() gives us an easy way to you use the power of Streams on Optional elements:

java.util.Optional.stream()为我们提供了一种简单的方法,可以在Optional元素上使用流的力量。

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

13. Conclusion

13.结论

Java 9 will come with a modular JVM and lots of other new and diverse improvements and features.

Java 9将配备一个模块化的JVM和许多其他新的和多样化的改进和功能。

You can find the source code for the examples over on GitHub.

你可以在GitHub上找到这些例子的源代码over