Java Record可以完全取代Lombok嗎?
譯者 | 胥磊
審校 | 梁策 孫淑娟
很長時間以來,Java 都因其冗長而受到一些開發者的詬病。哪怕是最熱衷 Java 的開發者或許也不得不承認,宣告一個只有兩個屬性的 bean 類Java讓人覺得有點可笑。因為如果遵循推薦規範,最終不僅添加了 getter 和 setter方法,還要新增toString, hashcode 和 equals 方法的重寫,最終大塊的樣板檔案式的程式碼逼得開發者想放棄Java語言。
Java
import java.util.Objects; public class Car { private String brand; private String model; private int year; public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getModel() { return model; } public void setModel(String model) { this.model = model; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } @Override public String toString() { return "Car{" + "brand='" + brand + '\'' + ", model='" + model + '\'' + ", year=" + year + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Car car = (Car) o; return year == car.year && Objects.equals(brand, car.brand) && Objects.equals(model, car.model); } @Override public int hashCode() { return Objects.hash(brand, model, year); } }
幸運的是,Lombok的橫空出世大大減輕了Java開發者的痛苦。但自從有了與其作用相似的Java Record型別,有人可能會問:Record是否可以全面取代Lombok呢?
1.Lombok是什麼?
Lombok是一個與開發環境高度整合的 Java 類庫(當然也可以看成一種語法糖),通過註解改進(spice)程式碼,它在 Java 社群中被廣泛接受和使用。
使用了Lombok後,我們新建一個名為Car的類是這樣的:
Java
import lombok.Data; @Data public class Car { private String brand; private String model; private int year; }
程式碼更加簡潔,同時也不會影響之前版本的任何功能。
2.Java Record是什麼?
定義的每一個Java Record型別可以簡單地看做是值物件(Value Object)模式的實現。它本質還是一個 Java 類,其中所有的屬性都是final的。所以在建立物件時所有類屬性都需要傳遞。Java Record是在 Java 14中引入的,它將持續改進,提升類設計。
通過Record新建Car類是這樣的:
Java
public record Car(String brand, String model, int year) {
與前一個版本對比,改進非常明顯。
下文將分析Lombok的一些特性,並通過和Record進行比較來評估是否可以永久讓Lombok退出歷史舞臺。
3.不可變性
Record預設情況下是不可變的,這意味著所有的類屬性都被隱式的宣告為 final。我們通常認為Record和值物件(Value Objects)很相似,但是它們沒有 setter 方法,所有的值都需要在建構函式中傳遞。Lombok可以使用@Value 註解達成同樣的效果,但也可以使用@Data註解來保持可變性。
Java
import lombok.Value; @Value public class Car { private String brand; private String model; private int year; }
4.Bean公約
Record並不打算遵循 bean的公約,獲取物件的方法不使用 getX 的方式命名,同時也不再提供 setter 方法和無參的建構函式。另一方面,Lombok只需使用@Data註解就可以將一個類輕鬆轉換為 JavaBean。
5.Builder
Builder構建器模式是改善物件、建立語法很棒的一種設計模式。Lombok為我們提供了@Builder這個很實用的註解,它幫我們實現了所有樣板程式碼。到目前為止,Java Record 並不打算提供此類實現。
Java
import lombok.Builder; @Builder public class Car { private String brand; private String model; private int year; public static void main(String[] args) { Car myCamaro = Car.builder() .brand("Chevrolet") .model("Camaro") .year(2022) .build(); } }
6.多fields類
Record只對少量fields的類是友好的。但是,如果再向其中新增10個fields,那麼得到的會是一個龐大的建構函式(繁多的入參),隨之而來的還有多參建構函式所帶來的固有的問題(傳參易錯位,方法過載難判斷等)。
Java
public record DetailedCar( String brand, String model, int year, String engineCode, String engineType, String requiredFuel, String fuelSystem, String maxHorsePower, String maxTorque, float fuelCapacity) { }
Java
DetailedCar camaroDetailed = new DetailedCar( "Chevrolet", "Camaro", 2022, "LTG", "Turbocharged", "Gas I4", "Direct Injection", "275 @ 560", "295 @ 3000-4500", 19.0f);
使用了Lombok,我們就可以決定建立bean類是選擇使用 setter來設定物件的狀態,還是使用builder這種更簡潔的方式來構造例項。唯一需要注意的是,因為其預設不會強制設定所有屬性,所以可能使例項處於屬性不完整狀態。當然@Builder 註解支援我們將類中所有屬性標記為@nonNull,這樣在構建時屬性就是必需的。如果必需屬性缺失設定則會在執行時丟擲一個異常,而不是編譯時強制丟擲異常。
Java
import lombok.Builder; import lombok.NonNull; @Builder public class DetailedCar { @NonNull private String brand; @NonNull private String model; @NonNull private int year; @NonNull private String engineCode; @NonNull private String engineType; @NonNull private String requiredFuel; @NonNull private String fuelSystem; @NonNull private String maxHorsePower; @NonNull private String maxTorque; @NonNull private float fuelCapacity; public static void main(String[] args) { DetailedCar camaroIncomplete = DetailedCar.builder() .brand("Chevrolet") .model("Camaro") .year(2022) .build(); } }
輸出:
Exception in thread "main" java.lang.NullPointerException: engineCode is marked non-null but is null
7.繼承
到目前為止,Java Record類是不支援繼承的,所以不能通過擴充套件其他Record類來建立一個新的Record類,這可能是模型設計的一個限制。儘管如此,我們也要認識到組合優於繼承(面向物件設計原則之七)。
Java
@Data @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class Car extends MotorVehicle { private String brand; private String model; private int year; }
8.結論
Record是Java的一個極佳的新特性,它正推動程式碼向更簡潔的方向發展,因此應該多多使用。對於提供了眾多功能的Lombok,考慮到Java變更的緩慢速度,要在專案中將其徹底取代似乎還為時尚早。
原文連結:http://dzone.com/articles/records-vs-lombok
譯者介紹
胥磊,51CTO社群編輯,某頭部電商技術副總監,關注Java後端開發,技術管理,架構優化,分散式開發等領域。
- Spring中實現非同步呼叫的方式有哪些?
- 帶引數的全型別 Python 裝飾器
- 整理了幾個Python正則表示式,拿走就能用!
- SOLID:開閉原則Go程式碼實戰
- React中如何引入CSS呢
- 一個新視角:前端框架們都卷錯方向了?
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 手寫程式語言-遞迴函式是如何實現的?
- 一文搞懂模糊匹配:定義、過程與技術
- 新來個阿里 P7,僅花 2 小時,做出一個多執行緒永動任務,看完直接跪了
- Puzzlescript,一種開發H5益智遊戲的引擎
- @Autowired和@Resource到底什麼區別,你明白了嗎?
- CSS transition 小技巧!如何保留 hover 的狀態?
- React如此受歡迎離不開這4個主要原則
- LeCun再炮轟Marcus: 他是心理學家,不是搞AI的
- Java保證執行緒安全的方式有哪些?
- 19個殺手級 JavaScript 單行程式碼,讓你看起來像專業人士
- Python 的"self"引數是什麼?
- 別整一坨 CSS 程式碼了,試試這幾個實用函式
- 再有人問你什麼是MVCC,就把這篇文章發給他!