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