一、Switch表達式
在先前的發布中,switch表達式只是一個「預覽」階段的特性。我想提醒一下,「預覽」階段的特性的目的是為了收集回饋,這些特性可能隨時改變,根據回饋結果,這些特性甚至可能會被移除,但通常所有預覽特性最後都會在Java中固定下來。
(推薦教學:java入門程式)
新的switch表達式的優點是,不再有預設跳過行為(fall-through),更全面,而且表達式和組合形式更容易編寫,因此出現bug的可能性就更低。例如,switch表達式現在可以使用箭頭語法,如下所示:
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; } };
二、文字區塊
Java 13引入的一個預覽功能是文字區塊。有了文字區塊,多行的字串字面量就很容易編寫了。這個功能在Java 14中進行第二次預覽,而且發生了一些變化。例如,多行文字的格式化可能需要編寫許多字串連接操作和轉義序列。下面的程式碼示範了一個HTML的範例:
String html = "<HTML>" + "\n\t" + "<BODY>" + "\n\t\t" + "<H1>\"Java 14 is here!\"</H1>" + "\n\t" + "</BODY>" + "\n" + "</HTML>";
有了文字區塊,就可以簡化這個過程,只需使用三引號作為文字區塊的起始和結束標記,就能寫出更優雅的程式碼:
String html = """ <HTML> <BODY> <H1>"Java 14 is here!"</H1> </BODY> </HTML>""";
與普通的字串字面量相比,文字區塊的表達性更好。
Java 14引進了兩個新的轉義序列。第一,可以使用新的 \s 轉義序列來表示一個空格。第二,可以使用反斜線 \ 來避免在行尾插入換行字元。這樣可以很容易地在文字區塊中將一個很長的行分解成多行來增加可讀性。
例如,現在寫多行字串的方式如下:
String literal = "Lorem ipsum dolor sit amet, consectetur adipiscing " + "elit, sed do eiusmod tempor incididunt ut labore " + "et dolore magna aliqua.";
在文字區塊中使用\ 轉義序列,就可以寫成這樣:
String text = """ Lorem ipsum dolor sit amet, consectetur adipiscing \ elit, sed do eiusmod tempor incididunt ut labore \ et dolore magna aliqua.\ """;
(影片教學推薦:java影片教學)
三、instanceof的模式匹配
Java 14引進了預覽特性,有了它就不再需要寫先透過instanceof判斷再強制轉換的程式碼了。例如,下面的程式碼:
if (obj instanceof Group) { Group group = (Group) obj; // use group specific methods var entries = group.getEntries(); }
利用這個預覽特性可以重構為:
if (obj instanceof Group group) { var entries = group.getEntries(); }
由於條件檢查要求obj為Group類型,為什麼還要像第一段程式碼一樣在條件碼在區塊中指明obj為Group型呢?這可能會引發錯誤。
這種更簡潔的語法可以去掉Java程式裡的大多數強制型別轉換。
JEP 305解釋了這個改變,並給出了Joshuoa Bloch的著作《Effective Java》中的一個例子,演示了下面兩種等價的寫法:
@Override public boolean equals(Object o) { return (o instanceof CaseInsensitiveString) && ((CaseInsensitiveString) o).s.equalsIgnoreCase(s); }
這段程式碼嗎中冗餘的CaseInsensitiveString強制類型轉換可以去掉,轉換成下面的方式:
@Override public boolean equals(Object o) { return (o instanceof CaseInsensitiveString cis) && cis.s.equalsIgnoreCase(s); }
這個預覽特性很值得嘗試,因為它打開了通往更通用的模式匹配的大門。模式匹配的想法是為語言提供一個便捷的語法,根據特定的條件從物件中提取組成部分。這正是instanceof操作符的用例,因為條件就是類型檢查,提取操作需要呼叫適當的方法,或存取特定的欄位。
換句話說,該預覽功能只是個開始,以後該功能肯定能夠減少更多的程式碼冗餘,從而降低bug發生的可能性。
四、Record
另一個預覽功能就是record。與前面介紹的其他預覽功能一樣,這個預覽功能也順應了減少Java冗餘程式碼的趨勢,並能幫助開發者寫出更精準的程式碼。 Record主要用於特定領域的類,它的位移功能就是儲存數據,而沒有任何自訂的行為。
我們開門見山,舉一個最簡單的領域類別的例子:BankTransaction,它表示一次交易,包含三個欄位:日期,金額,以及描述。定義類別的時候需要考慮多個面向:
建構器getter方法toString()hashCode()和equals()這些部分的程式碼通常由IDE自動生成,而且會佔用很大篇幅。以下是產生的完整的BankTransaction類別:
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); } }
Java 14提供了一種方法可以解決這種冗餘,可以更清晰地表達目的:這個類別的唯一目的就是將資料整合在一起。 Record會提供equals、hashCode和toString方法的實作。因此,BankTransaction類別可以重構如下:
public record BankTransaction(LocalDate date,double amount, String description) {}
透過record,可以「自動」地得到equals,hashCode和toString的實現,還有建構器和getter方法。
想嘗試這個例子,需要用preview標誌編譯該檔案:
javac --enable-preview --release 14 BankTransaction.javarecord的欄位隱含為final。因此,record的欄位不能被重新賦值。但要注意的是,這並不代表整個record是不可變的,保存在欄位中的物件可以是可變的。
五、NullPointerException
#一些人认为,抛出NullPointerException异常应该当做新的“Hello World”程序来看待,因为NullPointerException是早晚会遇到的。玩笑归玩笑,这个异常的确会造成困扰,因为它经常出现在生产环境的日志中,会导致调试非常困难,因为它并不会显示原始的代码。例如,如下代码:
var name = user.getLocation().getCity().getName();
在Java 14之前,你可能会得到如下的错误:
Exception in thread "main" java.lang.NullPointerExceptionat NullPointerExample.main(NullPointerExample.java:5)
不幸的是,如果在第5行是一个包含了多个方法调用的赋值语句(如getLocation()和getCity()),那么任何一个都可能会返回null。实际上,变量user也可能是null。因此,无法判断是谁导致了NullPointerException。
在Java 14中,新的JVM特性可以显示更详细的诊断信息:
Exception in thread "main" java.lang.NullPointerException: Cannot invoke "Location.getCity()" because the return value of "User.getLocation()" is nullat NullPointerExample.main(NullPointerExample.java:5)
该消息包含两个明确的组成部分:
后果:Location.getCity()无法被调用原因:User.getLocation()的返回值为null增强版本的诊断信息只有在使用下述标志运行Java时才有效:
-XX:+ShowCodeDetailsInExceptionMessages
下面是个例子:
java -XX:+ShowCodeDetailsInExceptionMessages NullPointerExample
在以后的版本中,该选项可能会成为默认。
这项改进不仅对于方法调用有效,其他可能会导致NullPointerException的地方也有效,包括字段访问、数组访问、赋值等。
以上是java14有什麼新特性的詳細內容。更多資訊請關注PHP中文網其他相關文章!