1. 程式人生 > >Java14版本特性【一文了解】

Java14版本特性【一文了解】

![](https://cdn.jsdelivr.net/gh/wmyskxz/BlogImage01/Java14版本特性【一文了解】/image-20200822180206407.png) - **「MoreThanJava」** 宣揚的是 **「學習,不止 CODE」**,本系列 Java 基礎教程是自己在結合各方面的知識之後,對 Java 基礎的一個總回顧,旨在 **「幫助新朋友快速高質量的學習」**。 - 當然 **不論新老朋友** 我相信您都可以 **從中獲益**。如果覺得 **「不錯」** 的朋友,歡迎 **「關注 + 留言 + 分享」**,文末有完整的獲取連結,您的支援是我前進的最大的動力! # 特性總覽 以下是 Java 14 中的引入的部分新特性。關於 Java 14 新特性更詳細的介紹可參考[這裡](http://openjdk.java.net/projects/jdk/14/)。 語言及特性更改: - Switch 表示式-標準(JEP 361) - instanceof 的模式匹配-預覽(JEP 305) - 有用的 NullPointerExceptions(JEP 358) - record-預覽(JEP 359) - 文字塊-預覽(JEP 368) JVM 更改: - 針對 G1 NUMA 感知記憶體分配的優化(JEP 345) - 刪除併發標記掃描(CMS)垃圾收集器(JEP 363) - JFR 事件流(JEP 349) - macOS 上的 ZGC-實驗性(JEP 364) - Windows 上的 ZGC-實驗性(JEP 365) - 棄用 ParallelScavenge + SerialOld 的 GC 組合(JEP 366) 其他特性: - 打包工具(JEP 343) - 非易失性對映位元組緩衝區(JEP 352) - 棄用 Solaris 和 SPARC 埠(JEP 362) - 刪除 Pack200 工具和 API(JEP 367) - 外部儲存器訪問 API(JEP 370) # 一. Switch 表示式-標準(JEP 361) 在上兩個版本中保留的預留功能,如今終於在 Java 14 中獲得了永久性的地位。 - [Java 12](https://www.wmyskxz.com/2020/08/22/java12-ban-ben-te-xing-xiang-jie/) 為表達是引入了 Lambda 語法,從而允許使用多個大小寫標籤進行模式匹配,並防止出現導致冗長程式碼的錯誤。它還強制執行窮盡情況,如果沒有涵蓋所有輸入情況,則會丟擲編譯錯誤。 - [Java 13](https://www.wmyskxz.com/2020/08/22/java13-ban-ben-te-xing-xiang-jie/) 在第二個預覽版本使用了 `yield` 替代了原有的 `break` 關鍵字來返回表示式的返回值。 Java 14 現在終於使這些功能成為了標準: ```java String result = switch (day) { case "M", "W", "F" -> "MWF"; case "T", "TH", "S" -> "TTS"; default -> { if (day.isEmpty()) { yield "Please insert a valid day."; } else { yield "Looks like a Sunday."; } } }; System.out.println(result); ``` *注意,`yield` 不是 Java 中的新關鍵字,它僅用於 Switch 表示式中。* # 二. instanceof 的模式匹配-預覽(JEP 305) 在 Java 14 之前,我們用於 `instanceof-and-cast` 檢查物件的型別並將其轉換為變數。 ```java if (obj instanceof String) { // instanceof String s = (String) obj; // cast if("jdk14".equalsIgnoreCase(s)){ //... } }else { System.out.println("not a string"); } ``` 現在,在 Java 14 中,我們可以像這樣重構上面的程式碼: ```java if (obj instanceof String s) { // instanceof, cast and bind variable in one line. if("jdk4".equalsIgnoreCase(s)){ //... } }else { System.out.println("not a string"); } ``` 如果 `obj` 是的例項 `String`,則將其 `String` 強制轉換為繫結變數並分配給該繫結變數 `s`。 # 三. 有用的 NullPointerExceptions(JEP 358) 空指標異常是任何開發人員的噩夢。以前,直到 Java 13 為止,除錯臭名昭著的 NPE 都很棘手。開發人員不得不依靠其他除錯工具,或者手動計算為空的變數/ 方法,因為堆疊跟蹤只會顯示行號。 在 Java 14 之前: ```java String name = jd.getBlog().getAuthor() //Stacktrace Exception in thread "main" java.lang.NullPointerException at NullPointerExample.main(NullPointerExample.java:5) ``` Java 14 引入了新的 JVM 功能(帶`-XX:+ShowCodeDetailsInExceptionMessages`選項),它通過更具描述性的堆疊提供了更好的見解,如下所示: ```bash Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Blog.getAuthor()" because the return value of "Journaldev.getBlog()" is null at NullPointerExample.main(NullPointerExample.java:4) ``` **注意**:以上功能不是語言功能。這是對執行時環境的增強。 # 四. record-預覽(JEP 359) `record` 是儲存純資料的資料型別。引入 `record` 背後的想法是快速建立沒有樣板程式碼的簡單簡潔類。*(這有點類似 Kotlin 中的資料型別,這也是為什麼有言論說 [Java 逐漸 "Kotlin 化"](https://www.infoq.cn/article/YgPRotsrI1qSr8cxRGlq) 的原因之一)* 通常,Java 中的類需要您實現 `equals()`、`hashCode()`、`getters` 和 `setters` 方法。雖然某些 IDE 支援此類的自動生成,但是程式碼仍然很冗長。使用 `record` 您只需按照以下方式定義一個類。 ```java record Author(){} //or record Author (String name, String topic) {} ``` Java 編譯器將自動生成一個帶有建構函式、私有 `final` 欄位、訪問器和 `equals`、 `hashCode `和 `toString` 方法的類。上一類的自動生成的 `getter` 方法是 `name()` 和 `topic()`。 編譯之後,我們可以檢視上面 `record Author (String name, String topic){}` 語句,編譯器為我們自動生成的類: ```java final class Author extends java.lang.Record { private final java.lang.String name; private final java.lang.String topic; public Author(java.lang.String name, java.lang.String topic) { /* compiled code */ } public java.lang.String toString() { /* compiled code */ } public final int hashCode() { /* compiled code */ } public final boolean equals(java.lang.Object o) { /* compiled code */ } public java.lang.String name() { /* compiled code */ } public java.lang.String topic() { /* compiled code */ } } ``` 此外,我們可以通過以下方式向記錄新增其他欄位,方法和建構函式: ```java record Author (int id, String name, String topic) { static int followers; public static String followerCount() { return "Followers are "+ followers; } public String description(){ return "Author "+ name + " writes on "+ topic; } public Author{ if (id < 0) { throw new IllegalArgumentException( "id must be greater than 0."); } } } ``` `record` 內定義的其他建構函式稱為 Compact 建構函式。它不包含任何引數,只是規範本身建構函式的引數。 關於 `record` 需要注意的幾件事: - `record` 既不能擴充套件一個類,也不能被另一個類擴充套件。這是一個 `final class`。 - `record` 不能是抽象的。 - `record` 不能擴充套件任何其他類,也不能在主體內定義例項欄位。例項欄位只能在狀態描述中定義。 - 宣告的欄位是私有欄位和 `final` 欄位。 - `record` 定義中允許使用靜態欄位和方法。 ## record 類的引用欄位內的值可以被改變 值得注意的是,對於定義為物件的欄位,只有引用是不可變的。底層值可以修改。 下面顯示了修改 ArrayList 的一條記錄。可以看到,每當 ArrayList 被更改時,該值都會被修改。 ```bash jshell> record Author(String name, List topics){} | 已建立 記錄 Author jshell> var topicList = new ArrayList(Arrays.asList("Java")); topicList ==> [Java] jshell> var author = new Author("Wmyskxz", topicList); author ==> Author[name=Wmyskxz, topics=[Java]] jshell> topicList.add("Python"); $6 ==> true jshell> author.topics(); $7 ==> [Java, Python] jshell> ``` ## record 能實現介面 下面的程式碼顯示了一個實現有記錄介面的示例: ```java interface Information { String getFullName(); } record Author(String name, String topic) implements Information { public String getFullName() { return "Author "+ name + " writes on " + topic; } } ``` ## record 支援多個建構函式 記錄允許宣告多個有或沒有引數的建構函式,如下所示: ```java record Author(String name, String topic) { public Author() { this("NA", "NA"); } public Author(String name) { this(name, "NA"); } } ``` ## record 允許修改訪問器方法 雖然 `record` 為狀態描述中定義的欄位生成公共訪問方法,但它們也允許您在主體中重新定義訪問方法,如下所示: ```java record Author(String name, String topic) { public String name() { return "This article was written by " + this.name; } } ``` ## 在執行時檢查 record 及其元件 `record` 為我們提供了 `isRecord()` 和 `getRecordComponents()` 來檢查類是否是一條記錄,並檢視它的欄位和型別。下面展示了它是如何做到的: ```java jshell> record Author(String name, String topic){} | 已建立 記錄 Author jshell> var author = new Author("Wmyskxz", "MoreThanJava"); author ==> Author[name=Wmyskxz, topic=MoreThanJava] jshell> author.getClass().isRecord(); $3 ==> true jshell> author.getClass().getRecordComponents(); $4 ==> RecordComponent[2] { java.lang.String name, java.lang.String topic } jshell> ``` >**Tips**:雖然我們在上面的程式碼示例中向記錄添加了額外的欄位和方法,但請確保不要做得過火。記錄被設計為普通的資料載體,如果您想實現許多其他方法,最好回到常規類。 # 五. 文字塊-預覽(JEP 368) 文字塊是 [Java 13](https://www.wmyskxz.com/2020/08/22/java13-ban-ben-te-xing-xiang-jie/) 中的預覽功能,其目的是允許輕鬆建立多行字串文字。在輕鬆建立 HTML 和 JSON 或 SQL 查詢字串時很有用。 在 Java 14 中,文字塊仍在預覽中,並增加了一些新功能。我們現在可以使用: - `\` 反斜槓用於顯示美觀的多行字串塊。 - `\s` 用於考慮尾隨空格,預設情況下編譯器會忽略它們。它保留了前面的所有空間。 ```java String text = """ Did you know \ Java 14 \ has the most features among\ all non-LTS versions so far\ """; String text2 = """ line1 line2 \s line3 """; String text3 = "line1\nline2 \nline3\n" //text2 and text3 are equal. ``` # 六. 針對 G1 NUMA 感知記憶體分配的優化(JEP 345) 新的 [NUMA感知記憶體](https://en.wikipedia.org/wiki/Non-uniform_memory_access) 分配模式提高了大型計算機上的 G1 效能。新增 `+XX:+UseNUMA` 選項以啟用它。 # 七. 刪除併發標記掃描(CMS)垃圾收集器(JEP 363) [Java 9 – JEP 291](https://openjdk.java.net/jeps/291) 已棄用此併發標記掃描(CMS)垃圾收集器,現在正式將其刪除。 ```bash /usr/lib/jvm/jdk-14/bin/java -XX:+UseConcMarkSweepGC Test OpenJDK 64-Bit Server VM warning: Ignoring option UseConcMarkSweepGC; support was removed in 14.0 ``` # 八. JFR 事件流(JEP 349) JDK Flight Recorder(JFR)是用於收集有關正在執行的 Java 應用程式的診斷和效能分析資料的工具。通常,我們開始記錄,停止記錄,然後將記錄的事件轉儲到磁碟以進行分析,它可以很好地進行概要分析,分析或除錯。 該 JEP 改進了現有的 JFR 以支援事件流,這意味著現在我們可以實時傳輸 JFR 事件,而無需將記錄的事件轉儲到磁碟並手動解析它。 # 九. macOS 上的 ZGC-實驗性(JEP 364) [Java 11 – JEP 333](https://openjdk.java.net/jeps/333) 在 Linux 上引入了 Z 垃圾收集器(ZGC),現在可移植到 macOS。 # 十. Windows 上的 ZGC-實驗性(JEP 365) [Java 11 – JEP 333](https://openjdk.java.net/jeps/333) 在 Linux 上引入了 Z 垃圾收集器(ZGC),現在可移植到 Windows版本 >= 1803 的機器上。 # 十一. 棄用 ParallelScavenge + SerialOld 的 GC 組合(JEP 366) 由於較少的使用和大量的維護工作,Java 14 不贊成使用並行年輕代和序列老一代 GC 演算法的組合。 ```bash /usr/lib/jvm/jdk-14/bin/java -XX:-UseParallelOldGC Test OpenJDK 64-Bit Server VM warning: Option UseParallelOldGC was deprecated in version 14.0 and will likely be removed in a future release. ``` # 十二. 其他特性 ## 打包工具(JEP 343) `jpackage `是將 Java 應用程式打包到特定於平臺的程式包中的新工具。 - Linux:deb 和 rpm - macOS:pkg 和 dmg - Windows:MSI 和 EXE 例如,將 `JAR` 檔案打包到支援 `exe` 的 Windows 平臺上。 ## 非易失性對映位元組緩衝區(JEP 352) 改進的 `FileChannel` API 可建立 `MappedByteBuffer` 對 [非易失性儲存器(NVM)的](https://en.wikipedia.org/wiki/Non-volatile_memory) 訪問,該儲存器即使在關閉電源後也可以檢索儲存的資料。例如,此功能可確保將可能仍在快取記憶體中的所有更改寫回到記憶體中。 *ps:僅 Linux / x64 和 Linux / AArch64 OS 支援此功能!* ## 棄用 Solaris 和 SPARC 埠(JEP 362) 不再支援 Solaris / SPARC,Solaris / x64 和 Linux / SPARC 埠,更少的平臺支援意味著更快地交付新功能。 ## 刪除 Pack200 工具和 API(JEP 367) [Java 11 – JEP 336](https://openjdk.java.net/jeps/336) 不贊成使用 `pack200` 和 `unpack200` 工具,以及軟體包中的 `Pack200` API `java.util.jar`,現在正式將其刪除。 ## 外部儲存器訪問 API(JEP 370) 孵化器模組,允許 Java API 訪問 Java 堆外部的外部記憶體。 外部儲存器訪問 API 引入了三個主要抽象: - MemorySegment:提供對具有給定範圍的連續記憶體區域的訪問。 - MemoryAddress:提供到 MemorySegment 的偏移量(基本上是一個指標)。 - MemoryLayout:提供一種描述記憶體段佈局的方法,該方法大大簡化了使用 `var` 控制代碼訪問 MemorySegment 的過程。使用此方法,不必根據記憶體的使用方式來計算偏移量。例如,一個整數或長整數陣列的偏移量將有所不同,但將使用 MemoryLayout 透明地對其進行處理。 **下面是一個例子:** ```java import jdk.incubator.foreign.*; import java.lang.invoke.VarHandle; import java.nio.ByteOrder; public class Test { public static void main(String[] args) { VarHandle intHandle = MemoryHandles.varHandle(int.class, ByteOrder.nativeOrder()); try (MemorySegment segment = MemorySegment.allocateNative(1024)) { MemoryAddress base = segment.baseAddress(); System.out.println(base); // print memory address intHandle.set(base, 999); // set value 999 into the foreign memory System.out.println(intHandle.get(base)); // get the value from foreign memory } } } ``` 編譯並使用孵化器模組執行 `jdk.incubator.foreign`。 ```bash $ /usr/lib/jvm/jdk-14/bin/javac --add-modules jdk.incubator.foreign Test.java warning: using incubating module(s): jdk.incubator.foreign 1 warning $ /usr/lib/jvm/jdk-14/bin/java --add-modules jdk.incubator.foreign Test WARNING: Using incubator modules: jdk.incubator.foreign MemoryAddress{ region: MemorySegment{ id=0x4aac6dca limit: 1024 } offset=0x0 } 999 ``` >進一步閱讀:官方文件 - https://download.java.net/java/GA/jdk14/docs/api/jdk.incubator.foreign/jdk/incubator/foreign/package-summary.html # 參考資料 1. OpenJDK 官方說明 - http://openjdk.java.net/projects/jdk/14/ 2. What is new in Java 14 - https://mkyong.com/java/what-is-new-in-java-14/ 3. Java 14 Features | JournalDev - https://www.journaldev.com/37273/java-14-features # 文章推薦 1. 這都JDK15了,JDK7還不瞭解? - https://www.wmyskxz.com/2020/08/18/java7-ban-ben-te-xing-xiang-jie/ 2. 全網最通透的 Java 8 版本特性講解 - https://www.wmyskxz.com/2020/08/19/java8-ban-ben-te-xing-xiang-jie/ 3. Java9的這些史詩級更新你都不知道? - https://www.wmyskxz.com/2020/08/20/java9-ban-ben-te-xing-xiang-jie/ 4. 你想了解的 JDK 10 版本更新都在這裡 - https://www.wmyskxz.com/2020/08/21/java10-ban-ben-te-xing-xiang-jie/ 5. 這裡有你不得不瞭解的 Java 11 特性 - https://www.wmyskxz.com/2020/08/22/java11-ban-ben-te-xing-xiang-jie/ 6. Java 12 版本特性【一文了解】 - https://www.wmyskxz.com/2020/08/22/java12-ban-ben-te-xing-xiang-jie/ 7. Java 13 版本特性【一文了解】 - https://www.wmyskxz.com/2020/08/22/java13-ban-ben-te-xing-xiang-jie/ 8. 「MoreThanJava」系列文集 - https://www.wmyskxz.com/categories/MoreThanJava/ > - 本文已收錄至我的 Github 程式設計師成長系列 **【More Than Java】,學習,不止 Code,歡迎 star:[https://github.com/wmyskxz/MoreThanJava](https://github.com/wmyskxz/MoreThanJava)** > - **個人公眾號** :wmyskxz,**個人獨立域名部落格**:wmyskxz.com,堅持原創輸出,下方掃碼關注,2020,與您共同成長! ![](https://cdn.jsdelivr.net/gh/wmyskxz/img/img/common/qrcode.png) 非常感謝各位人才能 **看到這裡**,如果覺得本篇文章寫得不錯,覺得 **「我沒有三顆心臟」有點東西** 的話,**求點贊,求關注,求分享,求留言!** 創作不易,各位的支援和認可,就是我創作的最大動力,我們下篇文