不要錯(cuò)過(guò)的六個(gè)優(yōu)秀Java新功能
譯文【51CTO.com快譯】隨著采用新的發(fā)布節(jié)奏,Java在2018年悄然經(jīng)歷了其開(kāi)發(fā)過(guò)程中最大的變化之一。而這個(gè)大膽的新計(jì)劃導(dǎo)致Java的開(kāi)發(fā)人員每六個(gè)月發(fā)布一個(gè)新功能。
這有利于保持Java的新鮮度和相關(guān)性,但它很容易讓開(kāi)發(fā)人員錯(cuò)過(guò)引入的功能。本文匯總了幾個(gè)有用的新功能并對(duì)其進(jìn)行概述。
1.可選類(Optional class)
空指針異常是所有錯(cuò)誤中最經(jīng)典的錯(cuò)誤之一。雖然開(kāi)發(fā)人員可能很熟悉這個(gè)問(wèn)題,但它的處理過(guò)程非常冗長(zhǎng),需要加以防范。至少在Java 8(以及Java 10改進(jìn))引入可選類之前是這樣。
本質(zhì)上,可選類允許包裝一個(gè)變量,然后使用包裝器的方法更簡(jiǎn)潔地處理空值。
清單1有一個(gè)多樣性空指針錯(cuò)誤的示例,其中的可選類引用foo為空(null),并且在其上訪問(wèn)了一個(gè)方法foo.getName()。
清單1.沒(méi)有可選類的空指針
- public class MyClass {
 - public static void main(String args[]) {
 - InnerClass foo = null;
 - System.out.println("foo = " + foo.getName());
 - }
 - }
 - class InnerClass {
 - String name = "";
 - public String getName(){
 - return this.name;
 - }
 - }
 
可選類提供了多種處理此類情況的方法,具體取決于開(kāi)發(fā)人員的需要。它運(yùn)行一個(gè)isPresent()方法,開(kāi)發(fā)人員可以使用它來(lái)進(jìn)行if檢查。然而這個(gè)過(guò)程可能相當(dāng)冗長(zhǎng)。但是可選類也有函數(shù)處理的方法。例如,清單2展示了如何使用ifPresent()——注意與isPresent()的一個(gè)字母差異,只有當(dāng)存在數(shù)值時(shí)才運(yùn)行輸出代碼。
清單2.只有當(dāng)存在數(shù)值時(shí)運(yùn)行代碼
- import java.util.Optional;
 - public class MyClass {
 - public static void main(String args[]) {
 - InnerClass foo = null; //new InnerClass("Test");
 - Optional fooWrapper = Optional.ofNullable(foo);
 - fooWrapper.ifPresent(x -> System.out.println("foo = " + x.getName()));
 - //System.out.println("foo = " + fooWrapper.orElseThrow());
 - }
 - }
 - class InnerClass {
 - String name = "";
 - public InnerClass(String name){
 - this.name = name;
 - }
 - public String getName(){
 - return this.name;
 - }
 - }
 
提示:當(dāng)使用可選類時(shí),如果使用orElse()方法通過(guò)方法調(diào)用提供默認(rèn)值,需要考慮如果該值是非空的話,使用orElseGet()來(lái)提供函數(shù)引用,以獲得不運(yùn)行調(diào)用的性能優(yōu)勢(shì)。
2.記錄類(預(yù)覽功能)
構(gòu)建Java應(yīng)用程序的一個(gè)常見(jiàn)需求是所謂的不可變DTO(數(shù)據(jù)傳輸對(duì)象)。DTO用于對(duì)來(lái)自數(shù)據(jù)庫(kù)、文件系統(tǒng)和其他數(shù)據(jù)存儲(chǔ)的數(shù)據(jù)進(jìn)行建模。傳統(tǒng)上,DTO是通過(guò)創(chuàng)建一個(gè)類來(lái)創(chuàng)建的,該類的成員通過(guò)構(gòu)造函數(shù)設(shè)置,沒(méi)有g(shù)etter方法來(lái)訪問(wèn)它們。Java 14引入并改進(jìn)了Java 15,新的記錄關(guān)鍵字為此目的提供了速記。
清單3說(shuō)明了引入記錄類型之前的典型DTO定義和用法。
清單3.一種簡(jiǎn)單的不可變DTO
- public class MyClass {
 - public static void main(String args[]) {
 - Pet myPet = new Pet("Sheba", 10);
 - System.out.println(String.format("My pet %s is aged %s", myPet.getName(), myPet.getAge()));
 - }
 - }
 - class Pet {
 - String name;
 - Integer age;
 - public Pet(String name, Integer age){
 - this.name = name;
 - this.age = age;
 - }
 - public String getName(){
 - return this.name;
 - }
 - public Integer getAge(){
 - return this.age;
 - }
 - }
 
可以使用記錄關(guān)鍵字消除大部分樣板文件,如清單4所示。
清單4.使用記錄關(guān)鍵字
- public class MyClass {
 - public static void main(String args[]) {
 - Pet myPet = new Pet("Sheba", 10);
 - System.out.println(String.format("My pet %s is aged %s", myPet.getName(), myPet.getAge()));
 - }
 - }
 - public record Pet(String name, Integer age) {}
 
需要注意的是,使用數(shù)據(jù)對(duì)象的客戶端代碼沒(méi)有改變;它的行為就像一個(gè)傳統(tǒng)定義的對(duì)象。記錄關(guān)鍵字足夠智能,可以通過(guò)簡(jiǎn)單的定義足跡推斷出存在哪些字段。
記錄類還定義了equals()、hashCode()和toString()的默認(rèn)實(shí)現(xiàn),同時(shí)還允許開(kāi)發(fā)人員覆蓋這些實(shí)現(xiàn)。開(kāi)發(fā)人員還可以提供自定義構(gòu)造函數(shù)。
需要注意的是,記錄不能被子類化。
3.新字符串方法
在Java 10和Java 12中,添加了幾個(gè)有用的新字符串方法。除了字符串操作方法之外,還引入了兩種用于簡(jiǎn)化文本文件訪問(wèn)的新方法。
Java 10中的新字符串方法:
- isBlank():如果字符串為空或字符串僅包含空格(包括制表符),則返回true。注意isBlank()與isEmpty()不同,后者僅在length為0時(shí)返回true。
 - lines():將字符串拆分為字符串流,每個(gè)字符串包含一行。每行由/r或/n或/r/n定義。例如,參見(jiàn)清單5。
 - strip()、stripLeading()、stripTrailing():分別從開(kāi)頭和結(jié)尾、僅開(kāi)頭和僅結(jié)尾刪除空格。
 - repeat(in ttimes):返回一個(gè)字符串,該字符串采用原始字符串并重復(fù)指定的次數(shù)。
 - readString():允許從文件路徑直接讀取字符串,如清單6所示。
 - writeString(Path path):將字符串直接寫入指定路徑的文件中。
 
Java 12中的新字符串方法:
- indent(int level):將字符串縮進(jìn)指定的數(shù)量。負(fù)值只會(huì)影響前導(dǎo)空格。
 - transform(Function f):將給定的lambda應(yīng)用于字符串。
 
清單5. String.lines() 示例
- import java.io.IOException;
 - import java.util.stream.Stream;
 - public class MyClass {
 - public static void main(String args[]) throws IOException{
 - String str = "test \ntest2 \n\rtest3 \r";
 - Stream lines = str.lines();
 - lines.forEach(System.out::println);
 - }
 - }
 - /*
 - outputs:
 - test
 - test2
 - test3
 - */
 
清單6.String.readString(Path path)示例
- Path path = Path.of("myFile.txt");
 - String text = Files.readString(path);
 - System.out.println(text);
 
4.Switch表達(dá)式
Java 12引入了Switch表達(dá)式,它允許在語(yǔ)句中內(nèi)聯(lián)使用Switch。換句話說(shuō),Switch表達(dá)式返回一個(gè)值。Java 12還提供了一種箭頭語(yǔ)法,無(wú)需顯式中斷即可防止失敗。Java 13則更進(jìn)一步改進(jìn),引入了yield關(guān)鍵字來(lái)明確表示Switch case返回的值。Java 14采用了新的Switch表達(dá)式語(yǔ)法作為完整功能。
讓我們看一些例子。首先,清單7有一個(gè)傳統(tǒng)格式(Java 8)的Switch語(yǔ)句示例。此代碼使用變量(消息)輸出已知數(shù)字的名稱。
清單7.傳統(tǒng)Java Switch
- class Main {
 - public static void main(String args[]) {
 - int size = 3;
 - String message = "";
 - switch (size){
 - case 1 :
 - message = "one";
 - case 3 :
 - message = "three";
 - break;
 - default :
 - message = "unknown";
 - break;
 - }
 - System.out.println("The number is " + message);
 - }
 - }
 
現(xiàn)在這段代碼非常冗長(zhǎng)并且挑剔。其實(shí)里面已經(jīng)有了錯(cuò)誤,開(kāi)發(fā)人員需要仔細(xì)查找丟失的內(nèi)容。清單8通過(guò)使用新Switch表達(dá)式進(jìn)行了簡(jiǎn)化。
清單8. 新的Switch表達(dá)式
- class NewSwitch {
 - public static void main(String args[]) {
 - int size = 3;
 - System.out.println("The number is " +
 - switch (size) {
 - case 1 -> "one";
 - case 3 -> "three";
 - default -> "unknown";
 - }
 - );
 - }
 - }
 
在清單8中,可以看到Switch表達(dá)式就在System.out.println調(diào)用中。這已經(jīng)是一個(gè)很大的可讀性勝利,并且消除了多余的消息變量。此外,箭頭語(yǔ)法通過(guò)消除break語(yǔ)句減少了代碼占用空間。(不使用箭頭語(yǔ)法時(shí)使用yield關(guān)鍵字。)
5.文本塊
Java 13通過(guò)引入文本塊解決了在Java中處理復(fù)雜文本字符串的長(zhǎng)期困擾。Java 14改進(jìn)了這種支持。
JSON、XML和SQL之類的東西可能會(huì)讓開(kāi)發(fā)人員過(guò)多地使用多個(gè)嵌套的轉(zhuǎn)義層。正如規(guī)范解釋的那樣:“在Java中,在字符串文字中嵌入HTML、XML、SQL或JSON的片段……通常需要使用轉(zhuǎn)義和連接進(jìn)行大量編輯,然后才能編譯包含該片段的代碼。該代碼段通常難以閱讀且難以維護(hù)。”
在清單9中,新的文本塊語(yǔ)法用于創(chuàng)建JSON片段。
清單9.使用文本塊的JSON
- class TextBlock {
 - public static void main(String args[]) {
 - String json = """
 - {
 - "animal" : "Quokka",
 - "link" : "https://en.wikipedia.org/wiki/Quokka"
 - }
 - """;
 - System.out.println(json);
 - }
 - }
 
在清單9中看不到轉(zhuǎn)義字符。此外,還要注意三重雙引號(hào)語(yǔ)法。
6.密封類
Java 15(JEP 260)引入了密封類的概念。簡(jiǎn)而言之,新的sealed關(guān)鍵字允許開(kāi)發(fā)人員定義哪些類可以對(duì)接口進(jìn)行子類化。在這種情況下,示例勝過(guò)千言萬(wàn)語(yǔ)。參見(jiàn)清單10。
清單10.密封類示例
- public abstract sealed class Pet
 - permits Cat, Dog, Quokka {...}
 
界面設(shè)計(jì)者在這里使用了sealed關(guān)鍵字來(lái)指定允許哪些類擴(kuò)展Pet類。
總的來(lái)說(shuō),很明顯,Java發(fā)布功能的新方法正在奏效。人們看到許多新想法通過(guò)JEP(JDK增強(qiáng)提案)過(guò)程轉(zhuǎn)化為實(shí)際可用的Java功能。這對(duì)Java開(kāi)發(fā)人員來(lái)說(shuō)是一個(gè)好消息。這意味著他們正在使用一種充滿活力、不斷發(fā)展的語(yǔ)言和平臺(tái)。
原文標(biāo)題:6 great new Java features you don’t want to miss,作者:Matthew Tyson
【51CTO譯稿,合作站點(diǎn)轉(zhuǎn)載請(qǐng)注明原文譯者和出處為51CTO.com】















 
 
 













 
 
 
 