Java Records 是否可以完全取代 Lombok 庫?

原文鏈接 丨h(huán)ttps://dzone.com/articles/records-vs-lombok
作者丨Gabriel?Solano
譯者丨W3CSChool編程獅
在過去很長的一段時(shí)間內(nèi),Java 總是因?yàn)槠淙唛L而遭受到開發(fā)者的詬病。即使是對Java有著最大熱情的開發(fā)者也不得不承認(rèn),聲明一個(gè)只有兩個(gè)屬性的bean類是一件荒謬的事情。
當(dāng)你按照推薦規(guī)范來書寫代碼,你不僅需要添加 getter 和 setter 方法,而且還要添加 toString、hashcode 以及 equals 方法的重寫。結(jié)果就是你獲得了一大塊的代碼,然后就開心愉快地去選擇另外一門語言。
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(String 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) && Object.equals(model, car.model);???}??@override??public int hashCode(){????return?Objects.hash(brand, model, year);??}}
值得慶幸的是,Lombok 庫的出現(xiàn)拯救了 Java 開發(fā)者,大大地減輕了編碼時(shí)的痛苦。但是,自從有了和 Lombok 相似功能的 Java Records 類,人們就很想知道現(xiàn)在能否用 Record 取代 Lombok?
它是一個(gè)與開發(fā)環(huán)境高度集成的 Java 庫,可以通過注釋改進(jìn)代碼。它在 Java 社區(qū)中被高度接受和使用。
使用了 Lombok,我們的 Car 類如下:
import?lombok.Data;@Datapublic class car{??private?String brand;??private String model;??private int year;}
代碼是不是變得更干凈,更令人賞心悅目。同時(shí),這樣寫也不會影響我們之前版本的所有功能。
定義的每一個(gè) Java Record 類型都可以被看作是值對象模式的實(shí)現(xiàn)。實(shí)質(zhì)上還是一個(gè) Java 類,其中所有實(shí)例都是不可變的。因此,在創(chuàng)建對象時(shí)所有類屬性都需要傳遞。Java Record 是在 Java 14 中引入的,幾乎可以肯定它將繼續(xù)發(fā)展來改進(jìn)類的設(shè)計(jì)。
通過 Record 創(chuàng)建的 Car 類如下:
public?record?Car(String?brand, String model, int year){}
和前面的版本相比,改進(jìn)得就更為明顯了。
下面將從 Lombok 的一些特性,并通過 Record 進(jìn)行比較,評估后者能否完全取代前者。
Record 在默認(rèn)情況下是不可變的,這就意味著所有的類屬性都會被隱式聲明為 final。我們通常會認(rèn)為 Record 和值對象很相似,但是它們沒有 setter 方法,所有的值都需要在構(gòu)造函數(shù)中傳遞。而 Lombok 可以通過@Value注釋來做同樣的事情,但也可以只使用@Data注釋來保持可變性。
impoprt lombok.Value;@Valuepublic?class?Car{??private?String?brand;??private?String model;??private int year;}
Record 并不意味著會遵循 Bean 公約,訪問器方法不使用 getX 命名,并且該類不提供 setter 或無參構(gòu)造函數(shù)。另一方面,對于 Lombok , 只需要使用@Data注釋即可以將類轉(zhuǎn)換為 Java Bean。
Builder 模式是一種很好的設(shè)計(jì)模式,可以改進(jìn)我們的對象創(chuàng)建語法。Lombok 提供了一個(gè)方便的注釋,它為我們實(shí)現(xiàn)了這個(gè)模式的所有樣板代碼。Java Records 目前不打算提供此實(shí)現(xiàn)。
import lombok.Builder;@Builderpublic class Cart{??private?String brand;??private String model;??private int year;??public?static?void?main(Stringp[] args){????Car?myCamaro?=?Car.builder()???? .brand("Chevrolet")??????.model("Camaro")??????.year(2022)??????.build();??}}
Record 只對少量參數(shù)的類是友好的。但是,如果再向其中添加 10 個(gè)參數(shù),那么得到的會是一個(gè)龐大的構(gòu)造函數(shù),隨之而來的還有多參構(gòu)造函數(shù)所帶來的固有的問題。
public?record?DetailedCar(??String brand, String model, int year,??String?engineCode,?String?engineType,?String?requireFuel,??String?fuelSystem,?String?maxHorsePower,?String?maxTorque,??float?fuelCapactiy??){}
DetailedCar camaroDetailed = new DetailedCar("Chevrolet", "Camaro", 2022, "LTG", "Turbocharged","Gas I4", "Direct Injection", "275 @ 560", "295 @ 3000-4500",19.0f);
使用了 Lombok,我們就可以決定創(chuàng)建 bean 類是選擇使用 setter來設(shè)置對象的狀態(tài),還是使用builder這種更簡潔的方式來構(gòu)造實(shí)例。唯一需要注意的是,因?yàn)槠淠J(rèn)不會強(qiáng)制設(shè)置所有屬性,所以可能使實(shí)例處于屬性不完整狀態(tài)。當(dāng)然@Builder 注解支持我們將類中所有屬性標(biāo)記為@nonNull,這樣在構(gòu)建時(shí)屬性就是必需的。如果必需屬性缺失設(shè)置則會在運(yùn)行時(shí)拋出一個(gè)異常,而不是編譯時(shí)強(qiáng)制拋出異常。
import lombok.Builder;import lombok.NonNull;public class DetailedCar {private String brand;private String model;private int year;private String engineCode;private String engineType;private String requiredFuel;private String fuelSystem;private String maxHorsePower;private String maxTorque;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目前,Java Record類是不支持繼承的,所以不能通過擴(kuò)展其他Record類來創(chuàng)建一個(gè)新的Record類,這可能是模型設(shè)計(jì)的一個(gè)限制。盡管如此,我們也要認(rèn)識到組合優(yōu)于繼承。
Lombok注釋可以參數(shù)化來考慮toString /hashCode/equals 方法中的父類屬性。
@Data@ToString(callSuper = true)@EqualsAndHashCode(callSuper = true)public class Car extends MotorVehicle {private String brand;private String model;private int year;}
Record 是Java 的一個(gè)非常棒的新特性,它正推動代碼向更簡潔的正確方向發(fā)展,因此應(yīng)該多使用 Record。但是,對于提供了眾多功能的Lombok,考慮到Java變更的緩慢速度,要在項(xiàng)目中將其徹底取代似乎還為時(shí)尚早。
以上就是關(guān)于 Record 能否完全取代 Lombok 的詳細(xì)內(nèi)容,Record 和 Lombok 你更鐘意哪一個(gè)?請?jiān)谠u論區(qū)留下你的看法。
這里是 W3CSchool 編程獅,點(diǎn)擊關(guān)注我們,閱讀更多IT資訊和技術(shù)干貨?~


課程:《Java基礎(chǔ)入門到框架時(shí)間》
講師介紹:丁鵬
課程介紹:Java是一門主流的、應(yīng)用廣泛的,功能強(qiáng)大且簡單易用的計(jì)算機(jī)編程語言。在所有的開發(fā)崗中,市場對Java的需求最多,同時(shí)Java工程師也數(shù)量龐大。
課程特點(diǎn):
1. 不要復(fù)制代碼,一定得自己敲;
2. 每節(jié)課程學(xué)完,要善于總結(jié)歸納;
3. 復(fù)習(xí)比學(xué)習(xí)更重要,務(wù)必打好基礎(chǔ);
學(xué)習(xí)方式:掃碼 ↓ 購買立即開始學(xué)習(xí)~

