lombok @Builder踩坑系列 - 構造方法和默認值問題

問題1:@Data和@Builder致使無參構造丟失

現象

  • 單獨使用@Data註解,是會生成無參數構造方法。
  • 單獨使用@Builder註解,發現生成了全屬性的構造方法。
  • @Data和@Builder一塊兒用:咱們發現沒有了默認的構造方法。若是手動添加無參數構造方法或者用@NoArgsConstructor註解都會報錯!

兩種解決方法

1. 構造方法加上@Tolerate 註解,讓lombok僞裝它不存在(不感知)

@Builder
@Data
public class TestLombok {

    @Tolerate
    TestLombok() {
    }
    ......
}

2. 直接加上這4個註解

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class TestLombok {
    ......
}

問題2:@Builder註解致使默認值無效

現象

使用Lombok註解能夠極高的簡化代碼量,比較好用的註解除了@Data以外,還有@Builder這個註解,它可讓你很方便的使用builder模式構建對象,可是今天發現@Builder註解會把對象的默認值清掉。java

@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)app

解決方案

只須要在字段上面加上@Builder.Default註解便可ui

@Builder.Default
private String aa = "zzzz";

緣由分析

咱們使用註解的方式,底層本質就是反射幫咱們生成了一系列的setter、getter,因此咱們直接打開編譯後的target包下面的.class文件,上面的全部緣由一目瞭然!
源文件:this

@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);
    }
}

對應的class字節碼:code

//
// 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等註解底層到底作了什麼,直接編譯當前文件,便可在生成的.class字節碼文件查看具體代碼便知道了對象

好比上述第二點,採用@Builder的時候,這個aa並無默認值,因此會爲空!!get

public TestLombok.TestLombokBuilder aa(String aa) {
            this.aa = aa;
            return this;
        }

總結

我的以爲若是想要使用@Builder,最簡單的方法就是直接寫上這4個註解,有默認值的話再加上@Builder.Default直接,正常狀況下就沒啥問題了!hash

@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);
    }
}
相關文章
相關標籤/搜索