Java9概述
Java9具有丰富的特性集。虽然没有新的语言概念,但是新的api和诊断命令肯定会引起开发人员的兴趣。
在本文中,我们将对一些新特性进行快速、高层次的研究;这里提供了新特性的完整列表。
模块化系统——Jigsaw项目
让我们从一个大问题开始——将模块化引入Java平台。
模块化系统提供类似于OSGi框架系统的功能。模块具有依赖性的概念,可以导出公共API并保持实现细节隐藏/私有。
这里的主要动机之一是提供模块化JVM,它可以在可用内存少得多的设备上运行。JVM只能运行应用程序所需的那些模块和api。有关这些模块的说明,请查看此链接。
另外,JVM内部(实现)api像com.sun.*
无法再从应用程序代码访问。
简单地说,这些模块将在一个名为module的文件中module-info.java位于java代码层次结构的顶部:
module com.baeldung.java9.modules.car {
requires com.baeldung.java9.modules.engines;
exports com.baeldung.java9.modules.car.handling;
}
我们的模块需要模块引擎运行,并出口一个处理包。
有关更深入的示例,请查看OpenJDK项目Jigsaw:modulesystem快速入门指南。
一个新的HTTP客户端
期待已久的旧HttpURLConnection
的替代品。
新的API位于java.net.http
包裹。
它应该同时支持HTTP/2协议和WebSocket握手,性能应该与apache http client、Netty和Jetty相当。
让我们通过创建和发送一个简单的HTTP请求来看看这个新功能。
更新:HTTP客户机JEP正在被移动到孵化器模块,因此它在包中不再可用java.net.http
而是在jdk.incubator.http
.
快速获取请求
API使用了生成器模式,这使得它非常易于快速使用:
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("http://postman-echo.com/get"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandler.asString());
进程 API
为控制和管理操作系统进程,对processapi进行了改进。
进程信息
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
子类提供了有关进程的详细信息。
销毁进程
现在–让我们使用destroy()
停止所有正在运行的子进程:
childProc = ProcessHandle.current().children();
childProc.forEach(procHandle -> {
assertTrue("Could not kill process " + procHandle.getPid(), procHandle.destroy());
});
其他的语言改进
Try-With-Resources
在Java7中,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) { }
Diamond运算符扩展
现在我们可以将Diamond运算符与匿名内部类结合使用:
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
};
接口私有方法
即将发布的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();
}
}}
JShell命令行工具
JShell是read–eval–print loop–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"
交互式shell具有历史记录和自动完成功能;它还提供保存到文件和从文件加载所有或部分书面语句的功能:
jshell> /save c:\develop\JShell_hello_world.txt
jshell> /open c:\develop\JShell_hello_world.txt
Hello JShell!
代码片段在文件加载时执行。
JCMD子命令
让我们研究一下jcmd命令行实用程序中的一些新子命令。我们将得到JVM中加载的所有类及其继承结构的列表。
在下面的示例中,我们可以看到java.lang.Socket
接口加载到运行Eclipse Neon的JVM中:
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标志:VM.flags -all
多分辨率图像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]);
Variable Handles
API位于java.lang.invoke
,由VarHandle
和MethodHandles
组成。它提供了java.util.concurrent.atomic
和sun.misc.Unsafe
对具有类似性能的对象字段和数组元素的操作。
用java9模块化系统访问sun.misc.Unsafe
从应用程序代码将不可能。
Publish-Subscribe 发布-订阅框架
java.util.concurrent.Flow
提供支持反应流发布-订阅框架的接口。这些接口支持跨多个运行在jvm上的异步系统的互操作性。
我们可以使用实用类SubmissionPublisher
来创建自定义组件。
统一JVM日志记录
这个特性为JVM的所有组件引入了一个通用的日志系统。它提供了进行日志记录的基础设施,但它没有添加来自所有JVM组件的实际日志记录调用。它也不向JDK中的Java代码添加日志记录。
日志框架定义了一组标记,例如gc、编译器、线程等。我们可以使用命令行参数-Xlog在启动期间打开日志记录。
让我们使用'debug'级别将带有'gc'标记的消息记录到名为'gc.txt文件“没有装饰:
java -Xlog:gc=debug:file=gc.txt:none ...
-Xlog:help
输出可能的选项和示例。可以在运行时使用jcmd命令修改日志配置。我们将把GC logs设置为info并将它们重定向到一个文件-gc_logs:
jcmd 9615 VM.log output=gc_logs what=gc
新的API
Immutable Set
java.util.Set.of()
–创建给定元素的不可变集。在Java8中,创建一组多个元素需要几行代码。现在我们可以做的很简单:
Set<String> strKeySet = Set.of("key1", "key2", "key3");
此方法返回的集合是JVM内部类:java.util.ImmutableCollections.SetN
,它扩展了公共java.util.AbstractSet
. 它是不可变的——如果我们尝试添加或删除元素,就会抛出UnsupportedOperationException。
也可以使用相同的方法将整个数组转换为一个集合。
Optional to Stream
java.util.Optional.stream()
为您在可选元素上使用流的方式提供了一种简单的方法:
List<String> filteredList = listOfOptionals.stream()
.flatMap(Optional::stream)
.collect(Collectors.toList());
除特别注明外,本站所有文章均为老K的Java博客原创,转载请注明出处来自https://javakk.com/1403.html
暂无评论