Java14版本特性【一文了解】
阿新 • • 發佈:2020-08-24
![](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)
非常感謝各位人才能 **看到這裡**,如果覺得本篇文章寫得不錯,覺得 **「我沒有三顆心臟」有點東西** 的話,**求點贊,求關注,求分享,求留言!**
創作不易,各位的支援和認可,就是我創作的最大動力,我們下篇文