1. 程式人生 > 資訊 >100g含23.4g蛋白質:肌肉小王子雞肉腸10袋13.9元

100g含23.4g蛋白質:肌肉小王子雞肉腸10袋13.9元

1、Lombok簡介   Lombok是一個外掛,其主要用途是提供了簡單的註解的形式來幫助我們簡化消除一些必須有但顯得很臃腫的 java 程式碼,提高編碼效率,使程式碼更簡潔。

  Lombok能以簡單的註解形式來簡化java程式碼,提高開發人員的開發效率。例如開發中經常需要寫的javabean,都需要花時間去新增相應的getter/setter,也許還要去寫構造器、equals等方法,而且需要維護,當屬性多時會出現大量的getter/setter方法,這些顯得很冗長也沒有太多技術含量,一旦修改屬性,就容易出現忘記修改對應方法的失誤。

  Lombok能通過註解的方式,在編譯時自動為屬性生成構造器、getter/setter、equals、hashcode、toString方法。

2、Lombok外掛安裝   想要使用 Lombok,必須要安裝一個 Lombok 外掛,不然的話,ide 編輯器會無法識別 Lombok 的註解,報找不到方法的異常。

  以 idea 為例,直接在工具中搜索 Lombok 外掛,然後安裝它。安裝完成後重啟 idea 開發工具即可。

  

  接下來,我們需要在使用 Lombok 的專案中引入 Lombok 的 jar 包。Maven 的 pom.xml 中引入以下配置:

org.projectlombok lombok 1.18.10 provided 3、Lombok註解   3.1、變數相關   3.1.1、val和var   lombok幫助java低階版本擁有jdk10的特性(在lombok 0.10引入)。

  使用var作為任何區域性變數宣告的型別(即使在for語句中),該型別將從初始化表示式中推斷出來(該型別推斷中不涉及對變數的任何進一步賦值)。例如:

var x=10.0; 將推斷double; var y=new arraylist(); 將推斷Arraylist;   注意:

對於複合型別,推斷出最常見的父類,而不是介面。例如,bool ? new HashSet() : new ArrayList()是一個帶有複合型別的表示式.存在同樣的父類:AbstractCollection,也實現了同樣的介面:Serializable。最終推斷的型別將是AbstractCollection,因為它是一個類,而Serializable是介面。 在不明確的情況下,例如當初始化表示式是null,將推斷為java.lang.Object 這是一個註釋型別,因為var x=10;將被解語法糖為@var int x=10; 注意:var 和 val 具有完全相同的語義,只是val變成@val   但是推薦使用val,因為idea具有val自帶的postfix template:

//使用示例 public String example() { val example = new ArrayList(); example.add("Hello, World!"); val foo = example.get(0); return foo.toLowerCase(); }   3.1.2、NonNull   在方法引數上:Lombok將在方法/建構函式體的開頭插入一個空檢查,並將引數的名稱作為訊息引發一個NullPointerException。

  在欄位上:任何為該欄位賦值的生成方法也將生成這些空檢查。

  例如:

public class DataExample { @NonNull private String name; }   編譯後的class為:

public class DataExample { public DataExample(@NonNull String name) { if (name == null) throw new NullPointerException("name is marked non-null but is null"); this.name = name; }

public void setName(@NonNull String name) {
    if (name == null)
        throw new NullPointerException("name is marked non-null but is null");
    this.name = name;
}

}   3.2、實體類相關   3.2.1、@Getter、@Setter   取代實體類中的get和set方法:可以在任何欄位上使用@Getter或@Setter,lombok會自動生成預設的getter / setter;如果在類上使用,則所有欄位生成getter / setter。

  AccessLevel:可以通過AccessLevel重寫訪問級別。

  關於欄位註釋(lombok v1.12.0中的新功能):將欄位上的javadoc複製到生成的getter和setter。

  關於方法命名:     getter:預設情況下方法名為:get+欄位名以駝峰連線;如果是boolean型別則:is+欄位名以駝峰連線。(Boolean型別是get開頭)。不建議使用is開頭的欄位命名,會產生混淆:

    setter:setter不受boolean影響:set+欄位名以駝峰連線。

  例如:

public class DataExample { @Setter(AccessLevel.PROTECTED) private String name; @Getter @Setter boolean flag; @Getter @Setter Boolean flagObj; }   編譯後的class為:

public class DataExample {private String name; boolean flag; Boolean flagObj; protected void setName(String name)

public boolean isFlag() {
    return this.flag;
}

public void setFlag(boolean flag) {
    this.flag = flag;
}

public Boolean getFlagObj() {
    return this.flagObj;
}

public void setFlagObj(Boolean flagObj) {
    this.flagObj = flagObj;
}

}   特殊事項:

@Getter可用於列舉而@Setter不能 來自流行庫的註釋檢查,例如javax.annotation.Nonnull,如果存在於欄位上,導致生成的setter中會進行顯式的空檢查。 當與@Accessors註解一起使用會產生影響   3.2.2、@Accessors   使用在類或欄位上,目的是修改getter和setter方法的內容(在lombok v0.11.0中作為實驗特徵引入)。

  功能:

fluent:如果為true,那麼getter 和setter 生成的方法名沒有字首。此外,除非指定,否則chain將為true。 chain:如果為true,則生成的setter返回this而不是void。預設值:false prefix:如果存在,則欄位必須以任何這些字首為字首。每個欄位名稱依次與列表中的每個字首進行比較,如果找到匹配項,則會剝離字首以建立欄位的基本名稱。在列表中包含一個空字串是合法的它將始終匹配。對於字母的字元,字首後面的字元不能是小寫字母,即以p為字首也不會匹配pepper,但是pEpper會被匹配上(並且意味著該欄位的基本名稱epper)。如果提供了字首列表並且欄位不以其中一個欄位開頭,則lombok將完全跳過該欄位,並將生成警告   示例如下:

@Getter @Setter public class AccessorsExample { @Accessors(fluent = true) private int age = 10;

@Accessors(prefix = "f")
private String fName;

@Accessors(chain = true)
private String chainName;

}   編譯後的class為:

public class AccessorsExample {

private int age = 10; private String fName; private String chainName;

public int age() { return this.age; }

public AccessorsExample age(int age) { this.age = age; return this; }

public String getName() { return this.fName; }

public void setName(String fName)

public AccessorsExample setChainName(String chainName) { this.chainName = chainName; return this; }

public String getChainName() { return this.chainName; } }   3.2.3、@AllArgsConstructor、RequiredArgsConstructor、@NoArgsConstructor   分別生成全參構造方法,帶參構造,無參構造。

  @NoArgsConstructor : 生成一個沒有引數的構造器。

  @AllArgsConstructor : 生成一個包含所有引數的構造器

  @RequiredArgsConstructor : 生成一個包含 "特定引數" 的構造器,特定引數指的是那些有加上 final 修飾詞的變數們或者加了@NonNull註解的引數。如果指定staticName = "of"引數,還會生成一個返回類物件的靜態工廠方法。

  如下例:

@RequiredArgsConstructor(staticName = "of") @AllArgsConstructor(access = AccessLevel.PROTECTED) public class ConstructorExample { private int x, y; @NonNull private T description; private final String finalString;

@NoArgsConstructor
public static class NoArgsExample {
    @NonNull private String field;
}

}   經過編譯後,class檔案反編譯,實際的類檔案等同於:

public class ConstructorExample { private int x; private int y; @NonNull private T description; private final String finalString;

private ConstructorExample(@NonNull T description, String finalString) {
    if (description == null)
        throw new NullPointerException("description is marked non-null but is null");
    this.description = description;
    this.finalString = finalString;
}

public static <T> ConstructorExample<T> of(@NonNull T description, String finalString) {
    return new ConstructorExample<>(description, finalString);
}

protected ConstructorExample(int x, int y, @NonNull T description, String finalString) {
    if (description == null)
        throw new NullPointerException("description is marked non-null but is null");
    this.x = x;
    this.y = y;
    this.description = description;
    this.finalString = finalString;
}

public static class NoArgsExample {
    @NonNull
    private String field;
}

}   這裡注意一個 Java 的小坑,當我們沒有指定構造器時,Java 編譯器會幫我們自動生成一個沒有任何引數的構造器給該類,但是如果我們自己寫了構造器之後,Java 就不會自動幫我們補上那個無引數的構造器了,然而很多地方(像是 Spring Data JPA),會需要每個類都一定要有一個無引數的構造器,所以你在加上 @AllArgsConstructor 時,一定要補上 @NoArgsConstrcutor,不然會有各種坑等著你。

  3.2.4、@ToString   類使用@ToString註解,Lombok會生成一個toString()方法,預設情況下,會輸出類名、所有屬性(會按照屬性定義順序),用逗號來分割。通過將includeFieldNames引數設為true,就能明確的輸出toString()屬性。這一點是不是有點繞口,通過程式碼來看會更清晰些。

  使用Lombok的示例:

@ToString(exclude="id") public class ToStringExample { private static final int STATIC_VAR = 10; private String name; private Shape shape = new Square(5, 10); private String[] tags; private int id;

@ToString(callSuper=true, includeFieldNames=true)
public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
        this.width = width;
        this.height = height;
    }
}

}   經過編譯後,class檔案反編譯,實際的類檔案等同於:

public class ToStringExample {

private int id;
private static final int STATIC_VAR = 10;
private String name;
private Shape shape = new Square(5, 10);
private String[] tags;

public String toString() {
    return "ToStringExample(name=" + getName() + ", shape=" + this.shape + ", tags=" + Arrays.deepToString((Object[])this.tags) + ")";
}

public static class Square extends Shape {
    private final int width;
    private final int height;

    public Square(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public String toString() {
        return "ToStringExample.Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";
    }
}

}   3.2.5、@EqualsAndHashCode   預設情況下,會使用所有非靜態(non-static)和非瞬態(non-transient)屬性來生成equals/canEqual和hasCode,也能通過exclude註解來排除一些屬性。

  使用Lombok的示例:

@EqualsAndHashCode(exclude={"id", "shape"}) public class EqualsAndHashCodeExample { private transient int transientVar = 10; private String name; private double score; private Shape shape = new Square(5, 10); private String[] tags; private int id;

@EqualsAndHashCode(callSuper=true)
public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public com.sun.javafx.geom.Shape impl_configShape() {
        return null;
    }
}

}   經過編譯後,class檔案反編譯,實際的類檔案等同於:

public class EqualsAndHashCodeExample {

private transient int transientVar = 10;
private int id;
private String name;
private double score;
private Shape shape = new Square(5, 10);
private String[] tags;


public int hashCode() {
    int PRIME = 59;
    result = 1;
    Object $name = getName();
    result = result * 59 + (($name == null) ? 43 : $name.hashCode());
    long $score = Double.doubleToLongBits(this.score);
    result = result * 59 + (int)($score >>> 32L ^ $score);
    return result * 59 + Arrays.deepHashCode((Object[])this.tags);
}

protected boolean canEqual(Object other) {
    return other instanceof EqualsAndHashCodeExample;
}

public boolean equals(Object o) {
    if (o == this)
        return true;
    if (!(o instanceof EqualsAndHashCodeExample))
        return false;
    EqualsAndHashCodeExample other = (EqualsAndHashCodeExample)o;
    if (!other.canEqual(this))
        return false;
    Object this$name = getName(), other$name = other.getName();
    return ((this$name == null) ? (other$name != null) : !this$name.equals(other$name)) ? 

         false : ((Double.compare(this.score, other.score) != 0) ? false : (!!Arrays.deepEquals((Object[])this.tags, (Object[])other.tags))); }

public static class Square extends Shape {
    private final int width;
    private final int height;

    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Square))
            return false;
        Square other = (Square)o;
        return !other.canEqual(this) ? false : (!super.equals(o) ? 

            false : ((this.width != other.width) ? false : (!(this.height != other.height)))); }

    protected boolean canEqual(Object other) {
        return other instanceof Square;
    }

    public int hashCode() {
        int PRIME = 59;
        result = super.hashCode();
        result = result * 59 + this.width;
        return result * 59 + this.height;
    }

    public Square(int width, int height) {
        this.width = width;
        this.height = height;
    }
}

}   3.2.6、@Data   作用在類上,相當於整合以下註解

@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode   其獨有屬性配置:

staticConstructor 靜態方法名:@Data(staticConstructor=“of”)通過新的方式來建立例項:Foo.of(5)   Lombok示例如下:

@Data public class DataExample { private final String name; @Setter(AccessLevel.PACKAGE) private int age; private double score; private String[] tags;

@ToString(includeFieldNames=true)
@Data(staticConstructor="of")
public static class Exercise<T> {
    private final String name;
    private final T value;
}

}   經過編譯後,class檔案反編譯,實際的類檔案等同於:

public class DataExample { private final String name; private int age; private double score; private String[] tags;

public DataExample(String name)

public String getName() { return this.name; }

void setAge(int age)

public int getAge() { return this.age; }

public void setScore(double score)

public double getScore() { return this.score; }

public String[] getTags() { return this.tags; }

public void setTags(String[] tags)

@Override public String toString() { return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + ")"; }

protected boolean canEqual(Object other) { return other instanceof DataExample; }

@Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof DataExample)) return false; DataExample other = (DataExample) o; if (!other.canEqual((Object)this)) return false; if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false; if (this.getAge() != other.getAge()) return false; if (Double.compare(this.getScore(), other.getScore()) != 0) return false; if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false; return true; }

@Override public int hashCode() { final int PRIME = 59; int result = 1; final long temp1 = Double.doubleToLongBits(this.getScore()); result = (resultPRIME) + (this.getName() == null ? 43 : this.getName().hashCode()); result = (resultPRIME) + this.getAge(); result = (resultPRIME) + (int)(temp1 ^ (temp1 >>> 32)); result = (resultPRIME) + Arrays.deepHashCode(this.getTags()); return result; }

public static class Exercise { private final String name; private final T value;

private Exercise(String name, T value) {
  this.name = name;
  this.value = value;
}

public static <T> Exercise<T> of(String name, T value) {
  return new Exercise<T>(name, value);
}

public String getName() {
  return this.name;
}

public T getValue() {
  return this.value;
}

@Override public String toString() {
  return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";
}

protected boolean canEqual(Object other) {
  return other instanceof Exercise;
}

@Override public boolean equals(Object o) {
  if (o == this) return true;
  if (!(o instanceof Exercise)) return false;
  Exercise<?> other = (Exercise<?>) o;
  if (!other.canEqual((Object)this)) return false;
  if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
  if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
  return true;
}

@Override public int hashCode() {
  final int PRIME = 59;
  int result = 1;
  result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
  result = (result*PRIME) + (this.getValue() == null ? 43 : this.getValue().hashCode());
  return result;
}

} }   通常 @Data 會加在一個值可以被更新的物件上,像是日常使用的 DTO 們、或是 JPA 裡的 Entity 們,就很適合加上 @Data 註解,也就是 @Data for mutable class。

  3.2.7、@Value   也是整合包,但是他會把所有的變數都設成 final 的,其他的就跟 @Data 一樣,等於同時加了以下註解:@ToString,@EqualsAndHashCode,@AllArgsConstructor,@FieldDefaults,@Getter。

  所有欄位由private和final修飾,不會產生setter方法。類本身也是由final修飾。

  建立Lombok示例如下:

@Value public class ValueExample { String name; @NonFinal int age; double score; protected String[] tags;

@ToString(includeFieldNames=true)
@Value(staticConstructor="of")
public static class Exercise<T> {
    String name;
    T value;
}

}   經過編譯後,class檔案反編譯,實際的類檔案等同於:

public final class ValueExample { private final String name;

private int age;

private final double score;

protected final String[] tags;

public ValueExample(String name, int age, double score, String[] tags) {
    this.name = name;
    this.age = age;
    this.score = score;
    this.tags = tags;
}

public boolean equals(Object o) {
    if (o == this)
        return true;
    if (!(o instanceof ValueExample))
        return false;
    ValueExample other = (ValueExample)o;
    Object this$name = getName(), other$name = other.getName();
    return ((this$name == null) ? (other$name != null) : !this$name.equals(other$name)) ? false : ((getAge() != other.getAge()) ? false : ((Double.compare(getScore(), other.getScore()) != 0) ? false : (!!Arrays.deepEquals((Object[])getTags(), (Object[])other.getTags()))));
}

public int hashCode() {
    int PRIME = 59;
    result = 1;    //不知道為什麼反編譯class會是這樣的寫法
    Object $name = getName();
    result = result * 59 + (($name == null) ? 43 : $name.hashCode());
    result = result * 59 + getAge();
    long $score = Double.doubleToLongBits(getScore());
    result = result * 59 + (int)($score >>> 32L ^ $score);
    return result * 59 + Arrays.deepHashCode((Object[])getTags());
}

public String toString() {
    return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString((Object[])getTags()) + ")";
}

public String getName() {
    return this.name;
}

public int getAge() {
    return this.age;
}

public double getScore() {
    return this.score;
}

public String[] getTags() {
    return this.tags;
}

public static final class Exercise<T> {
    private final String name;

    private final T value;

    public String toString() {
        return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")";
    }

    private Exercise(String name, T value) {
        this.name = name;
        this.value = value;
    }

    public static <T> Exercise<T> of(String name, T value) {
        return new Exercise<>(name, value);
    }

    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Exercise))
            return false;
        Exercise<?> other = (Exercise)o;
        Object this$name = getName(), other$name = other.getName();
        if ((this$name == null) ? (other$name != null) : !this$name.equals(other$name))
            return false;
        Object this$value = getValue(), other$value = other.getValue();
        return !((this$value == null) ? (other$value != null) : !this$value.equals(other$value));
    }

    public int hashCode() {
        int PRIME = 59;
        result = 1;    //不知道為什麼反編譯class會是這樣的寫法
        Object $name = getName();
        result = result * 59 + (($name == null) ? 43 : $name.hashCode());
        Object $value = getValue();
        return result * 59 + (($value == null) ? 43 : $value.hashCode());
    }

    public String getName() {
        return this.name;
    }

    public T getValue() {
        return this.value;
    }
}

}
  3.2.8、@Builder、@Singular   @Builder:通過內部類和一個全參構造器來實現構造者模式。

  @Singular:自動生成構造者模式程式碼,Singular是針對集合屬性的特殊處理。@Singular對集合進行操作,最終會生成不可變集合

不可變集合:底層是可變集合,但是修改時會丟擲異常。

  如示例:

@Builder public class SingularExample { private @Singular Set occupations; private @Singular("axis") ImmutableList axes; private @Singular SortedMap<Integer, T> elves; private @Singular Collection<?> minutiae; }   經過編譯後,class檔案反編譯,實際的類檔案等同於:

public class SingularExample { private Set occupations; private ImmutableList axes; private SortedMap<Integer, T> elves; private Collection<?> minutiae;

SingularExample(Set<String> occupations, ImmutableList<String> axes, SortedMap<Integer, T> elves, Collection<?> minutiae) {
    this.occupations = occupations;
    this.axes = axes;
    this.elves = elves;
    this.minutiae = minutiae;
}

public static <T extends Number> SingularExampleBuilder<T> builder() {
    return new SingularExampleBuilder<>();
}

public static class SingularExampleBuilder<T extends Number> {
    private ArrayList<String> occupations;
    private ImmutableList.Builder<String> axes;
    private ArrayList<Integer> elves$key;
    private ArrayList<T> elves$value;
    private ArrayList<Object> minutiae;

    public SingularExampleBuilder<T> occupation(String occupation) {
        if (this.occupations == null)
            this.occupations = new ArrayList<>();
        this.occupations.add(occupation);
        return this;
    }

    public SingularExampleBuilder<T> occupations(Collection<? extends String> occupations) {
        if (this.occupations == null)
            this.occupations = new ArrayList<>();
        this.occupations.addAll(occupations);
        return this;
    }

    public SingularExampleBuilder<T> clearOccupations() {
        if (this.occupations != null)
            this.occupations.clear();
        return this;
    }

    public SingularExampleBuilder<T> axis(String axis) {
        if (this.axes == null)
            this.axes = ImmutableList.builder();
        this.axes.add(axis);
        return this;
    }

    public SingularExampleBuilder<T> axes(Iterable<? extends String> axes) {
        if (this.axes == null)
            this.axes = ImmutableList.builder();
        this.axes.addAll(axes);
        return this;
    }

    public SingularExampleBuilder<T> clearAxes() {
        this.axes = null;
        return this;
    }

    public SingularExampleBuilder<T> elf(Integer elfKey, T elfValue) {
        if (this.elves$key == null) {
            this.elves$key = new ArrayList<>();
            this.elves$value = new ArrayList<>();
        }
        this.elves$key.add(elfKey);
        this.elves$value.add(elfValue);
        return this;
    }

    public SingularExampleBuilder<T> elves(Map<? extends Integer, ? extends T> elves) {
        if (this.elves$key == null) {
            this.elves$key = new ArrayList<>();
            this.elves$value = new ArrayList<>();
        }
        for (Map.Entry<? extends Integer, ? extends T> $lombokEntry : elves.entrySet()) {
            this.elves$key.add($lombokEntry.getKey());
            this.elves$value.add($lombokEntry.getValue());
        }
        return this;
    }

    public SingularExampleBuilder<T> clearElves() {
        if (this.elves$key != null) {
            this.elves$key.clear();
            this.elves$value.clear();
        }
        return this;
    }

    public SingularExampleBuilder<T> minutia(Object minutia) {
        if (this.minutiae == null)
            this.minutiae = new ArrayList();
        this.minutiae.add(minutia);
        return this;
    }

    public SingularExampleBuilder<T> minutiae(Collection<?> minutiae) {
        if (this.minutiae == null)
            this.minutiae = new ArrayList();
        this.minutiae.addAll(minutiae);
        return this;
    }

    public SingularExampleBuilder<T> clearMinutiae() {
        if (this.minutiae != null)
            this.minutiae.clear();
        return this;
    }

    public SingularExample<T> build() {
        Set<String> occupations;
        switch ((this.occupations == null) ? 0 : this.occupations.size()) {
            case false:
                occupations = Collections.emptySet();
                break;
            case true:
                occupations = Collections.singleton(this.occupations.get(0));
                break;
            default:
                occupations = new LinkedHashSet<>((this.occupations.size() < 1073741824) ? (1 + this.occupations.size() + (this.occupations.size() - 3) / 3) : Integer.MAX_VALUE);
                occupations.addAll(this.occupations);
                occupations = Collections.unmodifiableSet(occupations);
                break;
        }
        ImmutableList<String> axes = (this.axes == null) ? ImmutableList.of() : this.axes.build();
        SortedMap<Integer, T> elves = new TreeMap<>();
        if (this.elves$key != null)
            for (int $i = 0; $i < ((this.elves$key == null) ? 0 : this.elves$key.size()); ) {
                elves.put(this.elves$key.get($i), this.elves$value.get($i));
                $i++;
            }
        elves = Collections.unmodifiableSortedMap(elves);
        switch ((this.minutiae == null) ? 0 : this.minutiae.size()) {
            case false:
                minutiae = Collections.emptyList();
                return new SingularExample<>(occupations, axes, elves, minutiae);
            case true:
                minutiae = Collections.singletonList(this.minutiae.get(0));
                return new SingularExample<>(occupations, axes, elves, minutiae);
        }
        Collection<Object> minutiae = Collections.unmodifiableList(new ArrayList(this.minutiae));
        return new SingularExample<>(occupations, axes, elves, minutiae);
    }

    public String toString() {
        return "SingularExample.SingularExampleBuilder(occupations=" + this.occupations + ", axes=" + this.axes

           + ", elves$key=" + this.elves$key + ", elves$value=" + this.elves$value + ", minutiae=" + this.minutiae + ")"; } } }   注意:

雖然只要加上 @Builder 註解,我們就能夠用流式寫法快速設定物件的值,但是 setter 還是必須要寫不能省略的,因為 Spring 或是其他框架有很多地方都會用到物件的 getter/setter 對他們取值/賦值,所以通常是 @Data 和 @Builder 會一起用在同個類上,既方便我們流式寫程式碼,也方便框架做事。 由於Builder會生成一個全參構造器,導致預設的無參構造器失效,所以類採用@Builder註解後無法new出來。完美的避免方式:加上@AllArgsConstructor、@NoArgsConstructor後就可以同時使用new和構造者方式例項化物件了。 @Builder @AllArgsConstructor @NoArgsConstructor 父類中的屬性子類繼承問題:簡單解決方案是在子類中也手動寫該屬性   3.2.9、@Getter(lazy=true)   可以替代經典的Double Check Lock樣板程式碼,如下示例:

public class GetterLazyExample { @Getter(lazy = true) private final double[] cached = expensive(); private double[] expensive() { double[] result = new double[1000000]; for (int i = 0; i < result.length; i++) { result[i] = Math.asin(i); } return result; } }

//經過編譯,相當於以下這個class public class GetterLazyExample { private final AtomicReference