更新時間:2022-10-14 09:58:02 來源:動力節(jié)點 瀏覽1531次
Java 9 帶有豐富的特性集。雖然沒有新的語言概念,但新的 API 和診斷命令肯定會引起開發(fā)人員的興趣。
在這篇文章中,我們將對一些新功能進(jìn)行快速、高級的了解;此處提供了新功能的完整列表。
讓我們從最重要的開始——將模塊化引入 Java 平臺。
模塊化系統(tǒng)提供類似于 OSGi 框架系統(tǒng)的功能。模塊具有依賴關(guān)系的概念,可以導(dǎo)出公共 API 并將實現(xiàn)細(xì)節(jié)隱藏/私有。
這里的主要動機(jī)之一是提供模塊化 JVM,它可以在可用內(nèi)存少得多的設(shè)備上運行。JVM 只能使用應(yīng)用程序所需的那些模塊和 API 運行。查看此鏈接以了解這些模塊是什么。
此外,無法再從應(yīng)用程序代碼訪問com.sun.*等 JVM 內(nèi)部(實現(xiàn))API 。
簡而言之,這些模塊將在位于 java 代碼層次結(jié)構(gòu)頂部的名為module-info.java的文件中進(jìn)行描述:
module com.baeldung.java9.modules.car {
requires com.baeldung.java9.modules.engines;
exports com.baeldung.java9.modules.car.handling;
}
我們的模塊車需要模塊引擎來運行并導(dǎo)出一個包進(jìn)行處理。
期待已久的舊HttpURLConnection替代品。
新 API 位于java.net.http包下。
它應(yīng)該支持HTTP/2 協(xié)議和WebSocket握手,其性能應(yīng)該可以與Apache HttpClient、Netty和Jetty相媲美。
讓我們通過創(chuàng)建和發(fā)送一個簡單的 HTTP 請求來看看這個新功能。
更新:HTTP 客戶端 JEP正在移至 Incubator 模塊,因此它不再在包java.net.http中可用,而是在jdk.incubator.http 下可用。
快速獲取請求
API 使用 Builder 模式,這使得快速使用變得非常容易:
HttpRequest request = HttpRequest.newBuilder()
.uri(new URI("https://postman-echo.com/get"))
.GET()
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandler.asString());
進(jìn)程 API 已針對控制和管理操作系統(tǒng)進(jìn)程進(jìn)行了改進(jìn)。
(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方法返回一個對象,表示當(dāng)前正在運行的 JVM 的進(jìn)程。Info子類提供有關(guān)該過程的詳細(xì)信息。
(2)銷毀進(jìn)程
現(xiàn)在 - 讓我們使用destroy()停止所有正在運行的子進(jìn)程:
childProc = ProcessHandle.current().children();
childProc.forEach(procHandle -> {
assertTrue("Could not kill process " + procHandle.getPid(), procHandle.destroy());
});
(1)試用資源
在 Java 7 中,try-with-resources語法要求為語句管理的每個資源聲明一個新變量。
在 Java 9 中還有一個額外的改進(jìn):如果資源被 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)鉆石運算符擴(kuò)展
現(xiàn)在我們可以將菱形運算符與匿名內(nèi)部類結(jié)合使用:
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)接口私有方法
即將發(fā)布的 JVM 版本中的接口可以具有私有方法,可用于拆分冗長的默認(rèn)方法:
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 是 read-eval-print 循環(huán)——簡稱 REPL。
簡而言之,它是一個交互式工具,用于評估 Java 的聲明、語句和表達(dá)式,以及一個 API。測試小代碼片段非常方便,否則需要使用main方法創(chuàng)建一個新類。
jshell可執(zhí)行文件本身可以在<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!
代碼片段在文件加載時執(zhí)行。
讓我們探索jcmd命令行實用程序中的一些新子命令。我們將獲得 JVM 中加載的所有類及其繼承結(jié)構(gòu)的列表。
在下面的示例中,我們可以看到運行 Eclipse Neon 的 JVM 中加載的java.lang.Socket的層次結(jié)構(gòu):
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命令的第一個參數(shù)是我們要在其上運行命令的 JVM 的進(jìn)程 ID (PID)。
另一個有趣的子命令是set_vmflag。我們可以在線修改一些JVM參數(shù),而不需要重啟JVM進(jìn)程和修改它的啟動參數(shù)。
您可以使用子命令jcmd 14056 VM.flags -all找出所有可用的 VM 標(biāo)志
接口java.awt.image.MultiResolutionImage將一組具有不同分辨率的圖像封裝到一個對象中。我們可以根據(jù)給定的 DPI 指標(biāo)和圖像轉(zhuǎn)換集檢索特定于分辨率的圖像變體,或者檢索圖像中的所有變體。
java.awt.Graphics類根據(jù)當(dāng)前顯示 DPI 指標(biāo)和任何應(yīng)用的轉(zhuǎn)換從多分辨率圖像中獲取變體。
java.awt.image.BaseMultiResolutionImage類提供了基本實現(xiàn):
BufferedImage[] resolutionVariants = ....
MultiResolutionImage bmrImage
= new BaseMultiResolutionImage(baseIndex, resolutionVariants);
Image testRVImage = bmrImage.getResolutionVariant(16, 16);
assertSame("Images should be the same", testRVImage, resolutionVariants[3]);
API 位于java.lang.invoke下,由VarHandle和MethodHandles組成。它在對象字段和數(shù)組元素上提供等效的java.util.concurrent.atomic和sun.misc.Unsafe操作,具有相似的性能。
使用 Java 9 Modular 系統(tǒng)將無法從應(yīng)用程序代碼訪問sun.misc.Unsafe 。
java.util.concurrent.Flow類提供了支持Reactive Streams發(fā)布-訂閱框架的接口。這些接口支持跨在 JVM 上運行的多個異步系統(tǒng)的互操作性。
我們可以使用實用程序類SubmissionPublisher來創(chuàng)建自定義組件。
此功能為 JVM 的所有組件引入了一個通用的日志記錄系統(tǒng)。它提供了進(jìn)行日志記錄的基礎(chǔ)設(shè)施,但它沒有添加來自所有 JVM 組件的實際日志記錄調(diào)用。它也不向 JDK 中的 Java 代碼添加日志記錄。
日志框架定義了一組標(biāo)簽——例如gc、編譯器、線程等。我們可以使用命令行參數(shù)-Xlog在啟動期間打開日志。
讓我們使用'debug'級別將帶有'gc'標(biāo)簽的消息記錄到一個名為'gc.txt'的文件中,沒有任何修飾:
java -Xlog:gc=debug:file=gc.txt:none ...
-Xlog:help將輸出可能的選項和示例。可以使用jcmd命令在運行時修改日志記錄配置。我們將設(shè)置 GC 日志為 info 并將它們重定向到一個文件 - gc_logs:
jcmd 9615 VM.log output=gc_logs what=gc
(1)不可變集
java.util.Set.of() – 創(chuàng)建給定元素的不可變集合。在 Java 8 中,創(chuàng)建一個由多個元素組成的 Set 需要幾行代碼。現(xiàn)在我們可以簡單地做到這一點:
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());