欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中Lombok的@Builder注解注意事項(xiàng)

 更新時(shí)間:2023年12月08日 09:04:09   作者:GeorgiaStar  
這篇文章主要介紹了Java中Lombok的@Builder注解注意事項(xiàng),使用Lombok也會(huì)造成很多問題,尤其@Builder 有個(gè)很大的坑,已經(jīng)見過好幾次由于使用@Builder注解導(dǎo)致默認(rèn)值失效的問題,如果測試時(shí)沒有在意這個(gè)問題,就很容易引發(fā)線上問題,需要的朋友可以參考下

前言

現(xiàn)在很多程序員都習(xí)慣使用Lombok來使代碼更加 “簡潔”。

但是使用Lombok也會(huì)造成很多問題,尤其@Builder 有個(gè)很大的坑,已經(jīng)見過好幾次由于使用@Builder注解導(dǎo)致默認(rèn)值失效的問題,如果測試時(shí)沒有在意這個(gè)問題,就很容易引發(fā)線上問題。

問題復(fù)現(xiàn)

我們隨便定義一個(gè)類Config,對其中兩個(gè)屬性設(shè)置默認(rèn)值。

import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class Config {
    private boolean isOpen = true;
    private String name;
    private int value = 20;
}
public class LombokDemo {
    public static void main(String[] args) {
        Config config = Config.builder().name("test").build();
        System.out.println(config);
    }
}

借助Builder模式創(chuàng)建Config類實(shí)例時(shí),僅設(shè)置name屬性,然后打印出實(shí)例

public class LombokDemo {
    public static void main(String[] args) {
        Config config = Config.builder().name("test").build();
        System.out.println(config);
    }
}

輸出結(jié)果如下。

Config(isOpen=false, name=test, value=0)

我們?yōu)閕sOpen及value屬性設(shè)置的默認(rèn)值失效了。

原因分析

想了解為什么會(huì)這樣,我們只需要查看使用Lombok的注解后的Config類的 class文件長啥樣就明白了。

@Builder通過Lombok的注解處理器,在編譯時(shí)會(huì)自動(dòng)生成一個(gè)靜態(tài)內(nèi)部類,這個(gè)內(nèi)部類就是所謂的builder類,它包含了和被注解的類中的屬性一一對應(yīng)的setter方法,并且在build()方法中返回一個(gè)被注解的類的對象。

這個(gè)builder類的代碼實(shí)現(xiàn)是通過Lombok生成的,所以我們不需要手動(dòng)編寫。

public class Config {
    private boolean isOpen = true;
    private String name;
    private int value = 20;
    Config(boolean isOpen, String name, int value) {
        this.isOpen = isOpen;
        this.name = name;
        this.value = value;
    }
    public static ConfigBuilder builder() {
        return new ConfigBuilder();
    }
    public boolean isOpen() {
        return this.isOpen;
    }
    public String getName() {
        return this.name;
    }
    public int getValue() {
        return this.value;
    }
    public void setOpen(boolean isOpen) {
        this.isOpen = isOpen;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public boolean equals(Object o) {
      // 省略
    }
    protected boolean canEqual(Object other) {
        return other instanceof Config;
    }
    public int hashCode() {
        // 省略
    }
    public String toString() {
        return "Config(isOpen=" + this.isOpen() + ", name=" + this.getName() + ", value=" + this.getValue() + ")";
    }
    public static class ConfigBuilder {
        private boolean isOpen;
        private String name;
        private int value;
        ConfigBuilder() {
        }
        public ConfigBuilder isOpen(boolean isOpen) {
            this.isOpen = isOpen;
            return this;
        }
        public ConfigBuilder name(String name) {
            this.name = name;
            return this;
        }
        public ConfigBuilder value(int value) {
            this.value = value;
            return this;
        }
        public Config build() {
            return new Config(this.isOpen, this.name, this.value);
        }
        public String toString() {
            return "Config.ConfigBuilder(isOpen=" + this.isOpen + ", name=" + this.name + ", value=" + this.value + ")";
        }
    }
}

可以看到,ConfigBuilder中isOpen和value屬性并沒有使用我們想要設(shè)置的默認(rèn)值。

調(diào)用build方法時(shí), ConfigBuilder會(huì)調(diào)用全參的構(gòu)造方法來構(gòu)造Config 對象。

解決方法

使用@Builder.Default注解來標(biāo)識(shí)帶默認(rèn)值的屬性

import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class SomeConfig {
	@Builder.Default
    private boolean isOpen = true;
    private String name;
    @Builder.Default
    private int value = 20;
}

修改后輸出結(jié)果如下

Config(isOpen=true, name=test, value=20)

為什么加了@Builder.Default注解就能解決問題呢,看一下編譯后的class文件就明白了

public class Config {
    private boolean isOpen;
    private String name;
    private int value;
    private static boolean $default$isOpen() {
        return true;
    }
    private static int $default$value() {
        return 20;
    }
    Config(boolean isOpen, String name, int value) {
        this.isOpen = isOpen;
        this.name = name;
        this.value = value;
    }
    public static ConfigBuilder builder() {
        return new ConfigBuilder();
    }
    public boolean isOpen() {
        return this.isOpen;
    }
    public String getName() {
        return this.name;
    }
    public int getValue() {
        return this.value;
    }
    public void setOpen(boolean isOpen) {
        this.isOpen = isOpen;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setValue(int value) {
        this.value = value;
    }
    public boolean equals(Object o) {
       // 省略
    }
    protected boolean canEqual(Object other) {
        return other instanceof Config;
    }
    public int hashCode() {
       // 省略
    }
    public String toString() {
        boolean var10000 = this.isOpen();
        return "Config(isOpen=" + var10000 + ", name=" + this.getName() + ", value=" + this.getValue() + ")";
    }
    public static class ConfigBuilder {
        private boolean isOpen$set;
        private boolean isOpen$value;
        private String name;
        private boolean value$set;
        private int value$value;
        ConfigBuilder() {
        }
        public ConfigBuilder isOpen(boolean isOpen) {
            this.isOpen$value = isOpen;
            this.isOpen$set = true;
            return this;
        }
        public ConfigBuilder name(String name) {
            this.name = name;
            return this;
        }
        public ConfigBuilder value(int value) {
            this.value$value = value;
            this.value$set = true;
            return this;
        }
        public Config build() {
            boolean isOpen$value = this.isOpen$value;
            if (!this.isOpen$set) {
                isOpen$value = Config.$default$isOpen();
            }
            int value$value = this.value$value;
            if (!this.value$set) {
                value$value = Config.$default$value();
            }
            return new Config(isOpen$value, this.name, value$value);
        }
        public String toString() {
            return "Config.ConfigBuilder(isOpen$value=" + this.isOpen$value + ", name=" + this.name + ", value$value=" + this.value$value + ")";
        }
    }
}

每個(gè)設(shè)置默認(rèn)值的屬性都會(huì)在Builder中加上是否設(shè)置的標(biāo)記,如果沒有主動(dòng)設(shè)置值,則調(diào)用Config中的默認(rèn)值的靜態(tài)方法進(jìn)行賦值,然后再調(diào)用Config全參構(gòu)造方法構(gòu)造該對象。

使用@Builder注解的缺點(diǎn)

  1. 如果在類上使用了@Builder 注解,那么你需要手動(dòng)添加一個(gè)無參構(gòu)造函數(shù),否則有些序列化框架需要通過newInstance構(gòu)造對象時(shí)會(huì)報(bào)錯(cuò)。
  2. 如果在類上使用了@Builder注解,就不能再在構(gòu)造函數(shù)或方法上使用 @Builder注解,否則會(huì)導(dǎo)致重復(fù)生成構(gòu)造器類
  3. 如果在類上使用了@Builder 注解,想給某個(gè)屬性設(shè)置一個(gè)默認(rèn)值,還需要在屬性上使用@Builder.Default 注解,否則默認(rèn)值會(huì)被忽略。
  4. 如果想讓子類繼承父類的屬性,那么你需要在子類的全參構(gòu)造函數(shù)上使用 @Builder注解,并且在父類上使用@AllArgsConstructor注解,否則子類的構(gòu)造器類不會(huì)包含父類的屬性

到此這篇關(guān)于Java中Lombok的@Builder注解注意事項(xiàng)的文章就介紹到這了,更多相關(guān)Lombok的@Builder注解內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論