新專案決定用 JDK 17了

2022-12-20 12:01:31

大家好,我是風箏,公眾號「古時的風箏」,專注於 Java技術 及周邊生態。
文章會收錄在 JavaNewBee 中,更有 Java 後端知識圖譜,從小白到大牛要走的路都在裡面。

最近在調研 JDK 17,並且試著將之前的一個小專案升級了一下,在測試環境跑了一段時間。最終,決定了,新專案要採用 JDK 17 了。

JDK 1.8:「不是說好了,他發任他發,你用 Java 8 嗎?」

不光是我呀,連 Spring Boot 都開始要擁護 JDK 17了,下面這一段是 Spring Boot 3.0 的更新紀錄檔。

Spring Boot 3.0 requires Java 17 as a minimum version. If you are currently using Java 8 or Java 11, you'll need to upgrade your JDK before you can develop Spring Boot 3.0 applications.

Spring Boot 3.0 需要 JDK 的最低版本就是 JDK 17,如果你想用 Spring Boot 開發應用,你需要將正在使用的 Java 8 或 Java 11升級到 Java 17。

選用 Java 17,概括起來主要有下面幾個主要原因:

1、JDK 17 是 LTS (長期支援版),可以免費商用到 2029 年。而且將前面幾個過渡版(JDK 9-JDK 16)去其糟粕,取其精華的版本;

2、JDK 17 效能提升不少,比如重寫了底層 NIO,至少提升 10% 起步;

3、大多數第三方框架和庫都已經支援,不會有什麼大坑;

4、準備好了,來吧。

拿幾個比較好玩兒的特性來說一下 JDK 17 對比 JDK 8 的改進。

密封類

密封類應用在介面或類上,對介面或類進行繼承或實現的約束,約束哪些型別可以繼承、實現。例如我們的專案中有個基礎服務包,裡面有一個父類別,但是介於安全性考慮,值允許專案中的某些微服務模組繼承使用,就可以用密封類了。

沒有密封類之前呢,可以用 final關鍵字約束,但是這樣一來,被修飾的類就變成完全封閉的狀態了,所有類都沒辦法繼承。

密封類用關鍵字 sealed修飾,並且在宣告末尾用 permits表示要開放給哪些型別。

下面宣告了一個叫做 SealedPlayer的密封類,然後用關鍵字 permits將整合許可權開放給了 MarryPlayer類。

public sealed class SealedPlayer permits MarryPlayer {
    public void play() {
        System.out.println("玩兒吧");
    }
}

之後 MarryPlayer 就可以繼承 SealedPlayer了。

public non-sealed class MarryPlayer extends SealedPlayer{
    @Override
    public void play() {
        System.out.println("不想玩兒了");
    }
}

繼承類也要加上密封限制。比如這個例子中是用的 non-sealed,表示不限制,任何類都可以繼承,還可以是 sealed,或者 final

如果不是 permits 允許的型別,則沒辦法繼承,比如下面這個,編譯不過去,會給出提示 "java: 類不得擴充套件密封類:org.jdk17.SealedPlayer(因為它未列在其 'permits' 子句中)"

public non-sealed class TomPlayer extends SealedPlayer {

    @Override
    public void play() {

    }
}

空指標異常

String s = null;
String s1 = s.toLowerCase();

JDK1.8 的版本下執行:

Exception in thread "main" java.lang.NullPointerException
	at org.jdk8.App.main(App.java:10)

JDK17的版本(確切的說是14及以上版本)

Exception in thread "main" java.lang.NullPointerException: Cannot invoke "String.toLowerCase()" because "s" is null
	at org.jdk17.App.main(App.java:14)

出現異常的具體方法和原因都一目瞭然。如果你的一行程式碼中有多個方法、多個變數,可以快速定位問題所在,如果是 JDK1.8,有些情況下真的不太容易看出來。

yield關鍵字

public static int calc(int a,String operation){
    var result = switch (operation) {
        case "+" -> {
            yield a + a;
        }
        case "*" -> {
            yield a * a;
        }
        default -> a;
    };
    return result;
}

換行文字塊

如果你用過 Python,一定知道Python 可以用 'hello world'"hello world"''' hello world '''""" hello world """ 四種方式表示一個字串,其中後兩種是可以直接支援換行的。

在 JDK 1.8 中,如果想宣告一個字串,如果字串是帶有格式的,比如回車、單引號、雙引號,就只能用跳脫符號,例如下面這樣的 JSON 字串。

String json = "{\n" +
        "  \"name\": \"古時的風箏\",\n" +
        "  \"age\": 18\n" +
        "}";

從 JDK 13開始,也像 Python 那樣,支援三引號字串了,所以再有上面的 JSON 字串的時候,就可以直接這樣宣告了。

String json = """
        {
          "name": "古時的風箏",
          "age": 18
        }
        """;

record記錄類

類似於 Lombok 。

傳統的Java應用程式通過建立一個類,通過該類的構造方法範例化類,並通過getter和setter方法存取成員變數或者設定成員變數的值。有了record關鍵字,你的程式碼會變得更加簡潔。

之前宣告一個實體類。

public class User {
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

使用 Record類之後,就像下面這樣。

public record User(String name) {

}

呼叫的時候像下面這樣

RecordUser recordUser = new RecordUser("古時的風箏");
System.out.println(recordUser.name());
System.out.println(recordUser.toString());

輸出結果

Record 類更像是一個實體類,直接將構造方法加在類上,並且自動給欄位加上了 getter 和 setter。如果一直在用 Lombok 或者覺得還是顯式的寫上 getter 和 setter 更清晰的話,完全可以不用它。

G1 垃圾收集器

JDK8可以啟用G1作為垃圾收集器,JDK9到 JDK 17,G1 垃圾收集器是預設的垃圾收集器,G1是兼顧老年代和年輕代的收集器,並且其記憶體模型和其他垃圾收集器是不一樣的。

G1垃圾收集器在大多數場景下,其效能都好於之前的垃圾收集器,比如CMS。

ZGC

從 JDk 15 開始正式啟用 ZGC,並且在 JDK 16後對 ZGC 進行了增強,控制 stop the world 時間不超過10毫秒。但是預設的垃圾收集器仍然是 G1。

設定下面的引數來啟用 ZGC 。

-XX:+UseZGC

可以用下面的方法檢視當前所用的垃圾收集器

JDK 1.8 的方法

jmap -heap 8877

JDK 1.8以上的版本

jhsdb jmap --heap --pid 8877

例如下面的程式採用 ZGC 垃圾收集器。

其他一些小功能

1、支援 List.of()、Set.of()、Map.of()和Map.ofEntries()等工廠方法範例化物件;

2、Stream API 有一些改進,比如 .collect(Collectors.toList())可以直接寫成 .toList()了,還增加了 Collectors.teeing(),這個挺好玩,有興趣可以看一下;

3、HttpClient重寫了,支援 HTTP2.0,不用再因為嫌棄 HttpClient 而使用第三方網路框架了,比如OKHTTP;

升級 JDK 和 IDEA

安裝 JDK 17,這個其實不用說,只是推薦一個網站,這個網站可以下載各種系統、各種版本的 JDK 。地址是 https://adoptium.net/。

還有,如果你想在 IDEA 上使用 JDK 17,可能要升級一下了,只有在 2021.02版本之後才支援 JDK 17。


如果覺得還不錯的話,給個推薦吧!

公眾號「古時的風箏」,Java 開發者,專注 Java 及周邊生態。堅持原創乾貨輸出,你可選擇現在就關注我,或者看看歷史文章再關注也不遲。長按二維條碼關注,跟我一起變優秀!