- 「MoreThanJava」 宣揚的是 「學習,不止 CODE」,本系列 Java 基礎教程是自己在結合各方面的知識之後,對 Java 基礎的一個總回顧,旨在 「幫助新朋友快速高質量的學習」。
- 當然 不論新老朋友 我相信您都可以 從中獲益。如果覺得 「不錯」 的朋友,歡迎 「關注 + 留言 + 分享」,文末有完整的獲取連結,您的支援是我前進的最大的動力!
特性總覽
以下是 Java 14 中的引入的部分新特性。關於 Java 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 為表達是引入了 Lambda 語法,從而允許使用多個大小寫標籤進行模式匹配,並防止出現導致冗長程式碼的錯誤。它還強制執行窮盡情況,如果沒有涵蓋所有輸入情況,則會丟擲編譯錯誤。
-
Java 13 在第二個預覽版本使用了
yield
替代了原有的break
關鍵字來返回表示式的返回值。
Java 14 現在終於使這些功能成為了標準:
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
檢查物件的型別並將其轉換為變數。
if (obj instanceof String) { // instanceof
String s = (String) obj; // cast
if("jdk14".equalsIgnoreCase(s)){
//...
}
}else {
System.out.println("not a string");
}
現在,在 Java 14 中,我們可以像這樣重構上面的程式碼:
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 之前:
String name = jd.getBlog().getAuthor()
//Stacktrace
Exception in thread "main" java.lang.NullPointerException
at NullPointerExample.main(NullPointerExample.java:5)
Java 14 引入了新的 JVM 功能(帶-XX:+ShowCodeDetailsInExceptionMessages
選項),它通過更具描述性的堆疊提供了更好的見解,如下所示:
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 化" 的原因之一)
通常,Java 中的類需要您實現 equals()
、hashCode()
、getters
和 setters
方法。雖然某些 IDE 支援此類的自動生成,但是程式碼仍然很冗長。使用 record
您只需按照以下方式定義一個類。
record Author(){}
//or
record Author (String name, String topic) {}
Java 編譯器將自動生成一個帶有建構函式、私有 final
欄位、訪問器和 equals
、 hashCode
和 toString
方法的類。上一類的自動生成的 getter
方法是 name()
和 topic()
。
編譯之後,我們可以檢視上面 record Author (String name, String topic){}
語句,編譯器為我們自動生成的類:
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 */ }
}
此外,我們可以通過以下方式向記錄新增其他欄位,方法和建構函式:
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 被更改時,該值都會被修改。
jshell> record Author(String name, List<String> topics){}
| 已建立 記錄 Author
jshell> var topicList = new ArrayList<String>(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 能實現介面
下面的程式碼顯示了一個實現有記錄介面的示例:
interface Information {
String getFullName();
}
record Author(String name, String topic) implements Information {
public String getFullName() {
return "Author "+ name + " writes on " + topic;
}
}
record 支援多個建構函式
記錄允許宣告多個有或沒有引數的建構函式,如下所示:
record Author(String name, String topic) {
public Author() {
this("NA", "NA");
}
public Author(String name) {
this(name, "NA");
}
}
record 允許修改訪問器方法
雖然 record
為狀態描述中定義的欄位生成公共訪問方法,但它們也允許您在主體中重新定義訪問方法,如下所示:
record Author(String name, String topic) {
public String name() {
return "This article was written by " + this.name;
}
}
在執行時檢查 record 及其元件
record
為我們提供了 isRecord()
和 getRecordComponents()
來檢查類是否是一條記錄,並檢視它的欄位和型別。下面展示了它是如何做到的:
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 中的預覽功能,其目的是允許輕鬆建立多行字串文字。在輕鬆建立 HTML 和 JSON 或 SQL 查詢字串時很有用。
在 Java 14 中,文字塊仍在預覽中,並增加了一些新功能。我們現在可以使用:
\
反斜槓用於顯示美觀的多行字串塊。\s
用於考慮尾隨空格,預設情況下編譯器會忽略它們。它保留了前面的所有空間。
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感知記憶體 分配模式提高了大型計算機上的 G1 效能。新增 +XX:+UseNUMA
選項以啟用它。
七. 刪除併發標記掃描(CMS)垃圾收集器(JEP 363)
Java 9 – JEP 291 已棄用此併發標記掃描(CMS)垃圾收集器,現在正式將其刪除。
/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 在 Linux 上引入了 Z 垃圾收集器(ZGC),現在可移植到 macOS。
十. Windows 上的 ZGC-實驗性(JEP 365)
Java 11 – JEP 333 在 Linux 上引入了 Z 垃圾收集器(ZGC),現在可移植到 Windows版本 >= 1803 的機器上。
十一. 棄用 ParallelScavenge + SerialOld 的 GC 組合(JEP 366)
由於較少的使用和大量的維護工作,Java 14 不贊成使用並行年輕代和序列老一代 GC 演算法的組合。
/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)的 訪問,該儲存器即使在關閉電源後也可以檢索儲存的資料。例如,此功能可確保將可能仍在快取記憶體中的所有更改寫回到記憶體中。
ps:僅 Linux / x64 和 Linux / AArch64 OS 支援此功能!
棄用 Solaris 和 SPARC 埠(JEP 362)
不再支援 Solaris / SPARC,Solaris / x64 和 Linux / SPARC 埠,更少的平臺支援意味著更快地交付新功能。
刪除 Pack200 工具和 API(JEP 367)
Java 11 – JEP 336 不贊成使用 pack200
和 unpack200
工具,以及軟體包中的 Pack200
API java.util.jar
,現在正式將其刪除。
外部儲存器訪問 API(JEP 370)
孵化器模組,允許 Java API 訪問 Java 堆外部的外部記憶體。
外部儲存器訪問 API 引入了三個主要抽象:
- MemorySegment:提供對具有給定範圍的連續記憶體區域的訪問。
- MemoryAddress:提供到 MemorySegment 的偏移量(基本上是一個指標)。
- MemoryLayout:提供一種描述記憶體段佈局的方法,該方法大大簡化了使用
var
控制程式碼訪問 MemorySegment 的過程。使用此方法,不必根據記憶體的使用方式來計算偏移量。例如,一個整數或長整數陣列的偏移量將有所不同,但將使用 MemoryLayout 透明地對其進行處理。
下面是一個例子:
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
。
$ /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
參考資料
- OpenJDK 官方說明 - http://openjdk.java.net/projects/jdk/14/
- What is new in Java 14 - https://mkyong.com/java/what-is-new-in-java-14/
- Java 14 Features | JournalDev - https://www.journaldev.com/37273/java-14-features
文章推薦
- 這都JDK15了,JDK7還不瞭解? - https://www.wmyskxz.com/2020/08/18/java7-ban-ben-te-xing-xiang-jie/
- 全網最通透的 Java 8 版本特性講解 - https://www.wmyskxz.com/2020/08/19/java8-ban-ben-te-xing-xiang-jie/
- Java9的這些史詩級更新你都不知道? - https://www.wmyskxz.com/2020/08/20/java9-ban-ben-te-xing-xiang-jie/
- 你想了解的 JDK 10 版本更新都在這裡 - https://www.wmyskxz.com/2020/08/21/java10-ban-ben-te-xing-xiang-jie/
- 這裡有你不得不瞭解的 Java 11 特性 - https://www.wmyskxz.com/2020/08/22/java11-ban-ben-te-xing-xiang-jie/
- Java 12 版本特性【一文了解】 - https://www.wmyskxz.com/2020/08/22/java12-ban-ben-te-xing-xiang-jie/
- Java 13 版本特性【一文了解】 - https://www.wmyskxz.com/2020/08/22/java13-ban-ben-te-xing-xiang-jie/
- 「MoreThanJava」系列文集 - https://www.wmyskxz.com/categories/MoreThanJava/
- 本文已收錄至我的 Github 程式設計師成長系列 【More Than Java】,學習,不止 Code,歡迎 star:https://github.com/wmyskxz/MoreThanJava
- 個人公眾號 :wmyskxz,個人獨立域名部落格:wmyskxz.com,堅持原創輸出,下方掃碼關注,2020,與您共同成長!
非常感謝各位人才能 看到這裡,如果覺得本篇文章寫得不錯,覺得 「我沒有三顆心臟」有點東西 的話,求點贊,求關注,求分享,求留言!
創作不易,各位的支援和認可,就是我創作的最大動力,我們下篇文章見!