Java 14 開箱,它真香香香香
- 2020 年 3 月 26 日
- 筆記
Java 14 已經發布有一周時間了,我準備來開個箱,和小夥伴們一起來看看新特性裡面都有哪些好玩的。我們程式設計師應該抱著嘗鮮、獵奇的心態,否則就容易固步自封,技術停滯不前。先來看看 Java 14 都有哪些新特性吧!

紅色線划出來的是我比較感興趣的,其餘的對我沒什麼太大的吸引力,就暫且略過。
01、下載 JDK 14
要想開箱,得先下載 JDK 14,不然拿什麼開箱呢,對吧?有 2 處地方可供下載,Oracle 上可以下載商用版, jdk.java.net 上可以下載開源版。我們就選擇後者吧。

我目前用的是 Windows 作業系統,所以就選擇 Windows 版的 zip 包進行下載,完成後記得解壓。
02、升級 IntelliJ IDEA
需要把 IDEA 升級到搶先體驗版 2020.1 EAP,否則無法支援 Java 14 的新特性。

社區版的下載地址如下所示:
[https://www.jetbrains.com/idea/nextversion/#section=windows](https://www.jetbrains.com/idea/nextversion/#section=windows)
安裝的時候可以把之前的版本卸載,也可以選擇保留。完成後,我們來新建一個 Java 14 的項目。

01、instanceof
按照新特性的順序,我們就先從 instanceof 說起吧。舊式的 instanceof 的用法如下所示:
public class OldInstanceOf {
public static void main(String[] args) {
Object str = "Java 14,真香";
if (str instanceof String) {
String s = (String)str;
System.out.println(s.length());
}
}
}
需要先使用 instanceof 在 if 條件中判斷 str 的類型是否為 String(第一步),再在 if 語句中將 str 強轉為字元串類型(第二步),並且要重新聲明一個變數用於強轉後的賦值(第三步)。
三個步驟也不算多,但總覺得應該還有更好的語法,這不,Java 14 就想到了這一層。
public class NewInstanceOf {
public static void main(String[] args) {
Object str = "Java 14,真香";
if (str instanceof String s) {
System.out.println(s.length());
}
}
}
可以直接在 if 條件判斷類型的時候添加一個變數,就不需要再強轉和聲明新的變數了。是不是特別簡潔?但模式匹配的 instanceof 在 Java 14 中是預覽版的,默認是不啟用的,所以這段程式碼會有一個奇怪的編譯錯誤(Java 14 中不支援模式匹配的 instanceof)。

那怎麼解決這個問題呢?需要在項目配置中手動設置一下語言的版本。

設置完成後,編譯錯誤就隨風飄走了。程式輸出的結果如下所示:
10
不錯不錯,真香。想知道 Java 編譯器在背後幫我們做了什麼嗎?看一下反編譯後的位元組碼就明白了。
public class NewInstanceOf {
public NewInstanceOf() {
}
public static void main(String[] args) {
Object str = "Java 14,真香";
String s;
if (str instanceof String && (s = (String)str) == (String)str) {
System.out.println(s.length());
}
}
}
在 if 條件判斷前,先聲明了變數 s,然後在 if 條件中進行了強轉 s = (String)str)
,並且判斷了 s 和 str 是否相等。確實是一個解放開放者生產力的好特性,強烈希望這個特性在下個版本中轉正。
02、Records
在之前的一篇文章中,我談到了類的不可變性,它是這樣定義的:
public final class Writer {
private final String name;
private final int age;
public Writer(String name, int age) {
this.name = name;
this.age = age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
}
那麼,對於 Records 來說,一條 Record 就代表一個不變的狀態。儘管它會提供諸如 equals()
、hashCode()
、toString()
、構造方法,以及欄位的 getter,但它無意替代可變對象的類(沒有 setter),以及 Lombok 提供的功能。
來用 Records 替代一下上面這個 Writer 類:
public record Writer(String name, int age) { }
你看,一行程式碼就搞定。關鍵是比之前的程式碼功能更豐富,來看一下反編譯後的位元組碼:
public final class Writer extends java.lang.Record {
private final java.lang.String name;
private final int age;
public Writer(java.lang.String name, int age) { /* 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 int age() { /* compiled code */ }
}
類是 final 的,欄位是 private final 的,構造方法有兩個參數,toString()
、hashCode()
、equals()
方法也有了,getter 方法也有了,只不過沒有 get 前綴。但是沒有 setter 方法,也就是說 Records 確實針對的是不可變對象——鑒定完畢。那怎麼使用 Records 呢?
public class WriterDemo {
public static void main(String[] args) {
Writer writer = new Writer("沉默王二",18);
System.out.println("toString:" + writer);
System.out.println("hashCode:" + writer.hashCode());
System.out.println("name:" + writer.name());
System.out.println("age:" + writer.age());
Writer writer1 = new Writer("沉默王二", 18);
System.out.println("equals:" + (writer.equals(writer1)));
}
}
程式輸出的結果如下所示:
toString:Writer[name=沉默王二, age=18]
hashCode:1130697218
name:沉默王二
age:18
equals:true
不錯不錯,真香,以後定義不可變類時就簡單了,強烈希望這個特性在下個版本中轉正。
03、switch 表達式
關於 switch 表達式,我在之前的一篇文章中已經詳細說明了,點擊傳送門可以跳轉過去看看。兩周時間過去了,switch 表達式終於「媳婦熬成婆」,轉正了,恭喜恭喜。
記得這篇文章發表到掘金的時候,被噴子各種無腦 diss,說:「還以為你有什麼技巧,沒想到用的是 Java 13,可我們還停留在 Java 8 啊!」這顯然是一種固步自封的心態,非常不可取,程式設計師不應該這樣。一個最簡單的道理就是,Java 6 當年也很經典,不是被 Java 8 取代了嗎?隨著時間的推移,Java 8 早晚會被更劃時代的新版本取代——總要進步嘛。
關於 switch 表達式,這裡就簡單地搬個例子給你瞧瞧:
public class SwitchDemo {
enum PlayerTypes {
TENNIS,
FOOTBALL,
BASKETBALL,
PINGPANG,
UNKNOWN
}
public static void main(String[] args) {
System.out.println(createPlayer(PlayerTypes.BASKETBALL));
}
private static String createPlayer(PlayerTypes playerType) {
return switch (playerType) {
case TENNIS -> "網球運動員費德勒";
case FOOTBALL -> "足球運動員C羅";
case BASKETBALL -> "籃球運動員詹姆斯";
case PINGPANG -> "乒乓球運動員馬龍";
case UNKNOWN -> throw new IllegalArgumentException("未知");
};
}
}
除了可以使用 ->
的新式語法,還可以作為 return 結果,真香。
04、Text Blocks
在文本塊(Text Blocks)出現之前,如果我們需要拼接多行的字元串,就需要很多英文雙引號和加號,看起來就好像老太婆的裹腳布,非常不雅。如果恰好要拼接一些 HTML 格式的文本(原生 SQL 也是如此)的話,還要通過空格進行排版,通過換行轉義符 n
進行換行,這些繁瑣的工作對於一名開發人員來說,簡直就是災難。
public class OldTextBlock {
public static void main(String[] args) {
String html = "<html>n" +
" <body>n" +
" <p>Hello, world</p>n" +
" </body>n" +
"</html>n";
System.out.println(html);
}
}
Java 14 就完全不同了:
public class NewTextBlock {
public static void main(String[] args) {
String html = """
<html>
<body>
<p>Hello, world</p>
</body>
</html>
""";
System.out.println(html);
}
}
多餘的英文雙引號、加號、換行轉義符,統統不見了。僅僅是通過前後三個英文雙引號就實現了。我只能說,香,它真的香!

05、鳴謝
好了,我親愛的讀者朋友,以上就是本文的全部內容了,能看到這裡的就是最優秀的程式設計師。原創不易,莫要白票,請你為本文點贊個吧,這將是我寫作更多優質文章的最強動力。
如果覺得文章對你有點幫助,請微信搜索「 沉默王二 」第一時間閱讀,回復【666】【1024】更有我為你精心準備的 500G 高清教學影片(已分門別類),以及大廠技術牛人整理的面經一份,本文源碼已收錄在碼雲,傳送門~