使用Lombok的@Builder注解帶來的兩大坑
一、@Data和@Builder導(dǎo)致無參構(gòu)造丟失
- 單獨(dú)使用@Data注解,是會生成無參數(shù)構(gòu)造方法。
- 單獨(dú)使用@Builder注解,發(fā)現(xiàn)生成了全屬性的構(gòu)造方法。
@Data和@Builder一起用:我們發(fā)現(xiàn)沒有了默認(rèn)的構(gòu)造方法。如果手動添加無參數(shù)構(gòu)造方法或者用@NoArgsConstructor注解都會報錯!
兩種解決方法
1、構(gòu)造方法加上@Tolerate 注解,讓lombok假裝它不存在(不感知)。
@Builder @Data public class TestLombok { ? ? @Tolerate ? ? TestLombok() { ? ? } ? ? ...... } ? ?
2、直接加上這4個注解
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class TestLombok { ? ? ...... } ? ?
二、@Builder注解導(dǎo)致默認(rèn)值無效
使用Lombok注解可以極高的簡化代碼量,比較好用的注解除了@Data之外,還有@Builder這個注解,它可以讓你很方便的使用builder模式構(gòu)建對象,但是今天發(fā)現(xiàn)@Builder注解會把對象的默認(rèn)值清掉。
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class TestLombok { ? ? private String aa = "zzzz"; ? ? public static void main(String[] args) { ? ? ? ? TestLombok build = TestLombok.builder().build(); ? ? ? ? System.out.println(build); ? ? } }
輸出:
TestLombok(aa=null)
解決: 只需要在字段上面加上@Builder.Default注解即可
@Builder.Default private String aa = "zzzz";
三、分析原因
我們使用注解的方式,底層本質(zhì)就是反射幫我們生成了一系列的setter、getter,所以我們直接打開編譯后的target包下面的.class文件,上面的所有原因一目了然!
源文件:
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class TestLombok { ? ? private String aa = "zzzz"; ? ? public static void main(String[] args) { ? ? ? ? TestLombok build = TestLombok.builder().build(); ? ? ? ? System.out.println(build); ? ? } }
對應(yīng)的class字節(jié)碼:
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.apple.ucar; public class TestLombok { ? ? private String aa = "zzzz"; ? ? public static void main(String[] args) { ? ? ? ? TestLombok build = builder().build(); ? ? ? ? System.out.println(build); ? ? } ? ? public static TestLombok.TestLombokBuilder builder() { ? ? ? ? return new TestLombok.TestLombokBuilder(); ? ? } ? ? public String getAa() { ? ? ? ? return this.aa; ? ? } ? ? public void setAa(String aa) { ? ? ? ? this.aa = aa; ? ? } ? ? public boolean equals(Object o) { ? ? ? ? if (o == this) { ? ? ? ? ? ? return true; ? ? ? ? } else if (!(o instanceof TestLombok)) { ? ? ? ? ? ? return false; ? ? ? ? } else { ? ? ? ? ? ? TestLombok other = (TestLombok)o; ? ? ? ? ? ? if (!other.canEqual(this)) { ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? Object this$aa = this.getAa(); ? ? ? ? ? ? ? ? Object other$aa = other.getAa(); ? ? ? ? ? ? ? ? if (this$aa == null) { ? ? ? ? ? ? ? ? ? ? if (other$aa != null) { ? ? ? ? ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? } else if (!this$aa.equals(other$aa)) { ? ? ? ? ? ? ? ? ? ? return false; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? ? ? return true; ? ? ? ? ? ? } ? ? ? ? } ? ? } ? ? protected boolean canEqual(Object other) { ? ? ? ? return other instanceof TestLombok; ? ? } ? ? public int hashCode() { ? ? ? ? int PRIME = true; ? ? ? ? int result = 1; ? ? ? ? Object $aa = this.getAa(); ? ? ? ? int result = result * 59 + ($aa == null ? 43 : $aa.hashCode()); ? ? ? ? return result; ? ? } ? ? public String toString() { ? ? ? ? return "TestLombok(aa=" + this.getAa() + ")"; ? ? } ? ? public TestLombok() { ? ? } ? ? public TestLombok(String aa) { ? ? ? ? this.aa = aa; ? ? } ? ? public static class TestLombokBuilder { ? ? ? ? private String aa; ? ? ? ? TestLombokBuilder() { ? ? ? ? } ? ? ? ? public TestLombok.TestLombokBuilder aa(String aa) { ? ? ? ? ? ? this.aa = aa; ? ? ? ? ? ? return this; ? ? ? ? } ? ? ? ? public TestLombok build() { ? ? ? ? ? ? return new TestLombok(this.aa); ? ? ? ? } ? ? ? ? public String toString() { ? ? ? ? ? ? return "TestLombok.TestLombokBuilder(aa=" + this.aa + ")"; ? ? ? ? } ? ? } }
我們想知道@Data、@Builder等注解底層到底做了什么,直接編譯當(dāng)前文件,即可在生成的.class字節(jié)碼文件查看具體代碼便知道了
比如上述第二點(diǎn),采用@Builder的時候,這個aa并沒有默認(rèn)值,所以會為空??!
? public TestLombok.TestLombokBuilder aa(String aa) { ? ? ? ? ? ? this.aa = aa; ? ? ? ? ? ? return this; ? ? ? ? }
四、總結(jié)
個人覺得如果想要使用@Builder,最簡單的方法就是直接寫上這4個注解,有默認(rèn)值的話再加上@Builder.Default直接,正常情況下就沒啥問題了!
@Data @Builder @NoArgsConstructor @AllArgsConstructor public class TestLombok { ?? ?@Builder.Default ? ? private String aa = "zzzz"; ? ? public static void main(String[] args) { ? ? ? ? TestLombok build = TestLombok.builder().build(); ? ? ? ? System.out.println(build); ? ? } }
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring session 獲取當(dāng)前賬戶登錄數(shù)的實(shí)例代碼
這篇文章主要介紹了Spring session 獲取當(dāng)前賬戶登錄數(shù),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04Java如何使用while循環(huán)計算一個整數(shù)的位數(shù)
這篇文章主要介紹了Java使用while循環(huán)計算一個整數(shù)的位數(shù)方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01解決Spring導(dǎo)出可以運(yùn)行的jar包問題
最近需要解決Maven項目導(dǎo)入可執(zhí)行的jar包的問題,如果項目不包含Spring,那么使用mvn assembly:assembly即可,這篇文章主要介紹了Spring導(dǎo)出可以運(yùn)行的jar包,需要的朋友可以參考下2023-03-03spring注解識別一個接口的多個實(shí)現(xiàn)類方法
下面小編就為大家?guī)硪黄猻pring注解識別一個接口的多個實(shí)現(xiàn)類方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-04-04Java發(fā)送帶html標(biāo)簽內(nèi)容的郵件實(shí)例代碼
下面小編就為大家?guī)硪黄狫ava發(fā)送帶html標(biāo)簽內(nèi)容的郵件實(shí)例代碼。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-11-11用JAVA實(shí)現(xiàn)單鏈表,檢測字符串是否是回文串
這篇文章主要介紹了使用JAVA實(shí)現(xiàn)單鏈表,檢測字符串是否是回文串,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-11-11