公司要新做一個醫療行業的業務,經過業務端和產品端的評估該業務與公司已有的產品線關聯不大,用戶后續也不想在老系統那臺老爺車上繼續使用,話說老系統到現在差不多10年了,中間經歷過的前后端開發者形形色色,維護者換了一輪又一輪,系統已經日漸臃腫,頁面UI也不大美觀,作為技術研發人員也表示能夠理解。而且從技術的角度考慮,新系統中除了要研發的新業務外,它所依賴的基礎模塊與傳統的權限管理模式也大不相同,強行在原系統上研發的話,基礎模塊的重新搭建也是必不可少,到時候難免把原系統改的面目全非。經過綜合考慮覺得重新搭建一套系統,前后端應用均從0開始研發。
新搭建的項目那java8肯定是不能再用了,技術人員也要跟上時代進步的步伐,果斷安排上了springboot3和java17。說來也慚愧,我雖然是研發的老司機了,可新版本的jdk還沒有在項目中實際使用過,這次研發新項目方才真正實踐其中的一些新特性。
Records(數據類)
Records
是 Java 14 中作為預覽功能引入,并在 Java 16 中正式成為永久特性的新功能。它的主要目的是簡化不可變數據載體類(Data Carrier Class)的創建。這類類通常只包含數據字段,并提供訪問這些字段的方法,而沒有復雜的行為。
在 Records
出現之前,我們通常需要手動編寫一個 POJO(Plain Old Java Object)類,包含私有字段、構造函數、getter
方法、equals()
、hashCode()
和 toString()
方法。這不僅繁瑣,而且容易出錯。Records
正是為了解決這個問題而設計的。
1. 什么是 Record?
Record
是一種特殊的類,它代表其狀態是其唯一有意義的特征的不可變數據。它自動為你生成:
- 私有、
final
的字段:對應于record
頭部中聲明的組件。 - 公共構造函數:參數與
record
組件的順序和類型相同,用于初始化字段。 - 公共的
accessor
方法(訪問器):對于每個組件x
,會生成一個名為x()
的方法(注意:不是getX()
),返回該字段的值。 equals(Object o)
方法:基于所有字段的值進行比較。hashCode()
方法:基于所有字段的值生成哈希碼。toString()
方法:生成包含類名和所有字段名及其值的字符串表示。
2. 基本語法
public record Person(String name, int age) {// record body (可選)
}
這個簡單的聲明等價于以下傳統類:
// 等價的傳統寫法
public final class Person {private final String name;private final int age;public Person(String name, int age) {this.name = name;this.age = age;}public String name() { // 注意:是 name() 而不是 getName()return name;}public int age() { // 注意:是 age() 而不是 getAge()return age;}// 自動生成的 equals, hashCode, toString...// ... (代碼省略)
}
3. 使用 Record
public class RecordUseDemo {public static void main(String[] args) {// 創建 record 實例Person person = new Person("Alice", 30);// 訪問字段 (使用 accessor 方法)System.out.println(person.name()); // 輸出: AliceSystem.out.println(person.age()); // 輸出: 30// toString()System.out.println(person); // 輸出: Person[name=Alice, age=30]// equals() 和 hashCode()Person person2 = new Person("Alice", 30);System.out.println(person.equals(person2)); // 輸出: trueSystem.out.println(person.hashCode() == person2.hashCode()); // 輸出: true}
}
4. Record 的特性與限制
- 隱式
final
:Record
類是隱式final
的,不能被繼承。 - 隱式
public
:Record
類和其組件(字段)是隱式public
的。 - 不可變性:所有字段都是
private final
的,確保了Record
實例的不可變性。 - 無繼承:
Record
不能extends
其他類(因為它隱式繼承了java.lang.Record
)。 - 只能實現接口:
Record
可以implements
接口。 - 緊湊的構造函數:可以編寫“緊湊構造函數”來對參數進行驗證或預處理,但不能聲明自己的字段。
public record Person(String name, int age) {// 緊湊構造函數 - 用于驗證public Person {if (age < 0) {throw new IllegalArgumentException("Age cannot be negative");}// 注意:這里不能寫 this.name = name; 或 this.age = age;// 字段的賦值由編譯器自動完成// 你只能進行驗證或修改組件值(通過 this(...) 調用其他構造函數,但 record 通常只有一個構造函數)// 或者調用 super(...),但 record 沒有顯式父類構造函數可調用。}// 你也可以添加靜態方法或實例方法public boolean isAdult() {return age >= 18;}
}
- 可以添加方法:可以在
Record
中添加靜態方法、實例方法、甚至getter
/setter
(盡管setter
會破壞不可變性,不推薦)。
public record Point(int x, int y) {// 靜態方法public static Point origin() {return new Point(0, 0);}// 實例方法public double distanceToOrigin() {return Math.sqrt(x * x + y * y);}// 可以重寫自動生成的方法@Overridepublic String toString() {return "Point(" + x + ", " + y + ")";}
}
實踐示例
在數據層的Maaper中定義數據類User, 用于查詢接口的方法返回對象。
public interface MessageMapper {/*** 用戶對象* @param id* @param name*/record User(String id, String name) {}/*** 獲取發信人* @param messageId* @return*/User getSendUser(Long messageId);
}
Text Blocks(多行字符串)
使用三重引號("""
)定義多行字符串,避免轉義字符。簡便了大段的文本處理效率,不用再檢查字符串“+”拼接中的引號是否對稱等特殊字符字符轉義問題啦。
示例:
// java8 之前的寫法String s1 = "{\"name\":\"John\",\"age\":30}";// java 14 引入的寫法String s2= """{"name": "John","age": 30}""";
應用場景:JSON/XML配置、SQL語句拼接,提升可讀性。
Switch表達式
支持模式匹配和表達式返回值,替代傳統switch
語句。真是三目運算符的好幫手,寫過三目運算符的都知道,有時候僅僅是多一個值選項就不得不轉換為各種if else的嵌套寫法,可以這樣使用switch之后,寫法真的簡便很多。
示例:
int days=0;//java8 之前的寫法switch (month) {case "JANUARY":case "MARCH":case "MAY":case "JULY":case "AUGUST":case "OCTOBER":case "DECEMBER":days = 31;break;case "APRIL":case "JUNE":case "SEPTEMBER":case "NOVEMBER":days = 30;break;case "FEBRUARY":days = 28;break;default:System.out.println("Invalid month.");break;}//java14之后的寫法days = switch (month) {case "JANUARY", "MARCH", "MAY", "JULY", "AUGUST", "OCTOBER", "DECEMBER" -> 31;case "APRIL", "JUNE", "SEPTEMBER", "NOVEMBER" -> 30;case "FEBRUARY" -> 28;default -> throw new IllegalArgumentException("Invalid month: " + month);};
應用場景:狀態機處理(如訂單狀態流轉)。
以上就是我這邊的使用過程和經歷啦,后面項目中有其他特性應用再行補充和說明了。關于本文的內容和個人的使用經歷,也歡迎大家在評論區留言和交流。