Java 14 將於 3 月 17 號發佈,新特性一覽

  • 作者:Raoul-Gabriel Urma
    • 譯者:無明

    Java 14 計劃於 3 月 17 號發佈。這一版本包含的 JEP 比 Java 12 和 Java 13 的總和還要多。那麼,對於每天需要面對 Java 代碼的開發者來說,哪些東西最值得關注?

    本文將著重介紹以下這些 Java 新特性:

    • 改進的 switch 表達式。這一特性已經作為預覽版出現在 Java 12 和 Java 13 中,而 Java 14 將帶來它的完整正式版。
    • instanceof 的模式匹配(這是個一語言特性)。
    • 非常有用的 NullPointerException 信息(這是一個 JVM 特性)。

    switch 表達式

    在 Java 14 中,switch 表達式是一個正式的特性。而在之前的兩個 Java 版本中,這個特性只是預覽版。設定“預覽版”的目的是為了收集開發者反饋,並根據反饋結果決定相應的特性是否要做出修改,甚至是移除,但其中的大部分都會成為正式特性。

    新的 switch 表達式有助於減少 bug,因為它的表達和組合方式更容易編寫。例如,下面的示例使用了箭頭語法:

    <code>var log = switch (event) {
    case PLAY -> "User has triggered the play button";

    case STOP, PAUSE -> "User needs a break";
    default -> {
    String message = event.toString();
    LocalDateTime now = LocalDateTime.now();
    yield "Unknown event " + message +
    " logged on " + now;
    }
    };/<code>

    文本塊

    Java 13 引入了文本塊特性,並將其作為預覽版。有了這個特性,處理多行字符串字面量就容易了很多。在 Java 14 中,該特性仍然是預覽版,不過做了一些調整。在沒有這個特性之前,要表示多行格式化的字符串需要像下面這樣:


    <code>String html = "" +
    "\\n\\t" + "" +
    "\\n\\t\\t" + "

    \"Java 14 is here!\"

    " +
    "\\n\\t" + "" +
    "\\n" + "";/<code>

    有了文本塊特性之後,可以使用三引號來表示字符串的開頭和結尾,這樣的代碼看起來更簡潔、更優雅:

    <code>String html = """


    "Java 14 is here!"



    """;/<code>

    在 Java 14 中,該特性增加了兩個轉義字符。一個是\\s,用來表示單空格。一個是反斜槓\\,用在行末表示不換行。如果你有一個很長的字符串,為了讓代碼看起來更好看,但又不希望真的換行,就可以使用這個轉義字符。

    例如,目前的多行字符串是這樣的:

    <code>String literal = 
    "Lorem ipsum dolor sit amet, consectetur adipiscing " +
    "elit, sed do eiusmod tempor incididunt ut labore " +
    "et dolore magna aliqua.";/<code>

    使用了新的轉義字符之後是這樣的:

    <code>String text = """
    Lorem ipsum dolor sit amet, consectetur adipiscing \\
    elit, sed do eiusmod tempor incididunt ut labore \\
    et dolore magna aliqua.\\
    """;/<code>

    instanceof 的模式匹配

    為了避免在使用 instanceof 後還需要進行類型轉換,Java 14 引入了一個新的預覽版特性。例如,在沒有該特性之前:

    <code>if (obj instanceof Group) {
    Group group = (Group) obj;
    // 調用 group 的方法
    var entries = group.getEntries();
    }/<code>

    我們可以使用新的特性來重寫這段代碼:

    <code>if (obj instanceof Group group) {
    var entries = group.getEntries();
    }/<code>

    既然條件檢查已經確認 obj 是 Group 類型,那為什麼還要再次進行顯式的類型轉換呢?這樣有可能更容易出錯。新的語法可以將代碼中的大部分類型轉換移除掉。2011 年發佈的一份研究報告顯示,Java 代碼中有 24% 的類型轉換是跟在 instanceof 之後的。

    Joshua Bloch 的經典著作《Effective Java》中有一段代碼示例:

    <code>@Override public boolean equals(Object o) { 
    return (o instanceof CaseInsensitiveString) &&
    ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
    }/<code>

    這段代碼可以使用新的語法寫成:

    <code>@Override public boolean equals(Object o) { 
    return (o instanceof CaseInsensitiveString cis) &&
    cis.s.equalsIgnoreCase(s);
    }/<code>

    這個特性很有意思,因為它為更為通用的模式匹配打開了大門。模式匹配通過更為簡便的語法基於一定的條件來抽取對象的組件,而 instanceof 剛好是這種情況,它先檢查對象類型,然後再調用對象的方法或訪問對象的字段。

    記錄類(Record)

    另一個預覽特性是“記錄”。該特性主要是為了降低 Java 語法的“囉嗦”程度,讓開發者寫出更簡潔的代碼。這個特性主要用在某些領域類上,這些類主要用於保存數據,不提供領域行為。

    我們以一個簡單的領域類 BankTransaction 作為例子,它包含了三個字段:date、amount 和 description。目前,這個類需要以下幾個組件:

    • 構造器;
    • getter 方法;
    • toString() 方法;
    • hashCode() 和 equals() 方法。

    這些方法一般可以通過 IDE 自動生成,但會佔用很大的代碼空間,例如:

    <code>public class BankTransaction {
    private final LocalDate date;
    private final double amount;
    private final String description;


    public BankTransaction(final LocalDate date,
    final double amount,
    final String description) {
    this.date = date;
    this.amount = amount;
    this.description = description;
    }

    public LocalDate date() {
    return date;
    }

    public double amount() {
    return amount;
    }

    public String description() {
    return description;
    }

    @Override
    public String toString() {
    return "BankTransaction{" +
    "date=" + date +
    ", amount=" + amount +
    ", description='" + description + '\\'' +
    '}';
    }

    @Override

    public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    BankTransaction that = (BankTransaction) o;
    return Double.compare(that.amount, amount) == 0 &&
    date.equals(that.date) &&
    description.equals(that.description);
    }

    @Override
    public int hashCode() {
    return Objects.hash(date, amount, description);
    }
    }/<code>

    Java 14 提供了一種方式,可以避免這種繁瑣的代碼,滿足開發者希望一個類只是用來聚合數據的意圖。BankTransaction 可以重構成:

    <code>public record BankTransaction(LocalDate date,
    double amount,
    String description) {}/<code>

    除了構造器和 getter 方法,還會自動生成 equals、hashCode 和 toString 方法。

    要嘗試這個特性,需要在編譯代碼時打開預覽標籤:

    <code>javac --enable-preview --release 14 BankTransaction.java/<code>

    記錄類的字段隱式都是 final 的,也就是說不能對它們進行動態賦值。不過要注意,這並不意味著整個記錄類對象都是不可變的,如果字段保存的是對象,那麼這個對象是可變的。

    這裡要插一句話,如果從培訓的角度來講,例如你要教會初級開發者,那麼記錄類應該在什麼時候講授比較好?在介紹 OOP 和類的概念之前還是之後?

    有用的 NullPointerException 信息

    有些人認為,拋出 NullPointerException 應該成為 Java 編程的一個新的“Hello world”,因為這是不可避免的。NullPointerException 確實讓人抓狂,它們經常出現在生產環境的日誌裡,但調試起來很困難。例如,看看下面這段代碼:

    <code>var name = user.getLocation().getCity().getName();/<code>

    這段代碼可能會拋出一個異常:

    <code>\t
    Exception in thread "main" java.lang.NullPointerException
    at NullPointerExample.main(NullPointerExample.java:5)
    /<code>

    在一行代碼裡連續調用了多個方法,比如 getLocation() 和 getCity(),它們都有可能返回 null,而 user 也可能為 null。所以,我們無法知道是什麼導致了 NullPointerException。

    在 Java 14 中,JVM 會拋出更多有用的診斷信息:

    <code>Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Location.getCity()" because the return value of "User.getLocation()" is null
    at NullPointerExample.main(NullPointerExample.java:5)/<code>

    錯誤信息提供了兩個內容:

    • 結果:無法調用 Location.getCity()。
    • 原因:User.getLocation() 返回值是 null。

    要啟用這個功能,需要添加 JVM 標識:

    <code>-XX:+ShowCodeDetailsInExceptionMessages/<code>

    例如:

    <code>java -XX:+ShowCodeDetailsInExceptionMessages NullPointerExample/<code>

    據報道,在未來的版本中,這個特性可能會默認啟用。

    這個增強特性不僅適用於方法調用,只要會導致 NullPointerException 的地方也都適用,包括字段的訪問、數組的訪問和賦值。

    結論

    Java 14 帶來了一些新的預覽特性,例如可用於避免顯式類型轉換的 instanceof 模式匹配。它還引入了記錄類,提供了一種簡潔的方式來創建只用於聚合數據的類。另外,增強的 NullPointerException 錯誤信息有助於更好地進行診斷。switch 表達式成為 Java 14 的正式特性。文本塊進入第二輪預覽,新增了兩個轉義字符。

    英文原文

    Java 14 arrives with a host of new features
    https://blogs.oracle.com/javamagazine/java-14-arrives-with-a-host-of-new-features


    分享到:


    相關文章: