lombok的@Builder


@Builder

......鮑勃是你的叔叔:用於創建對象的無懈可擊的花式褲子!
@Builder 在lombok v0.12.0中作為實驗特征介紹。
@Builder獲得了@Singular支持,並lombok從lombok v1.16.0 升級到主程序包。
@Builder@Singular增加,因為龍目島v1.16.8一個明確的方法。
@Builder.Default 功能已在lombok v1.16.16中添加。

Overview

@Builder標注生產絡合劑的API為你的類。

@Builder 允許您使用以下代碼自動生成使您的類可實例化所需的代碼:
Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();

@Builder可以放在類,構造函數或方法上。雖然“在類上”和“在構造函數上”模式是最常見的用例,但@Builder最容易用“方法”用例來解釋。

@Builder(從現在開始調用目標)注釋的方法會導致生成以下7件事:

  • 一個名為的內部靜態類*Foo*Builder,具有與靜態方法相同的類型參數(稱為構建器)。
  • 構建器中目標的每個參數的一個私有非靜態非最終字段。
  • 構建器中:一個包私有no-args空構造函數。
  • 構建器中:對於目標的每個參數,類似於“setter”的方法:它具有與該參數相同的類型和相同的名稱。它返回構建器本身,以便可以鏈接setter調用,如上例所示。
  • 構建器中build()調用方法的方法,傳入每個字段。它返回與目標返回的相同類型。
  • 構建器中:一個明智的toString()實現。
  • 在包含目標的類中:一種builder()方法,它創建構建器的新實例。

如果該元素已經存在,則將以靜默方式跳過每個列出的生成元素(忽略參數計數並僅查看名稱)。這包括構建器本身:如果該類已經存在,則lombok將簡單地開始在此已存在的類中注入字段和方法,除非當然要存在要注入的字段/方法。您可能不會在構建器類上放置任何其他方法(或構造函數)生成lombok注釋; 例如,您不能放置@EqualsAndHashCode構建器類。

@Builder可以為集合參數/字段生成所謂的“奇異”方法。它們采用1個元素而不是整個列表,並將該元素添加到列表中。例如:Person.builder().job("Mythbusters").job("Unchained Reaction").build();將導致該List<String> jobs字段中包含2個字符串。要獲得此行為,需要使用注釋字段/參數@Singular。該功能有自己的文檔

既然“方法”模式已經清楚了,那么@Builder在構造函數上添加注釋的功能類似; 實際上,構造函數只是具有特殊語法來調用它們的靜態方法:它們的“返回類型”是它們構造的類,它們的類型參數與類本身的類型參數相同。

最后,應用於@Builder類就好像您已添加@AllArgsConstructor(access = AccessLevel.PACKAGE)到類中並將@Builder注釋應用於此all-args構造函數。這僅適用於您自己沒有編寫任何顯式構造函數的情況。如果您確實有一個顯式構造函數,請將@Builder注釋放在構造函數而不是類上。

如果使用@Builder生成構建器來生成自己的類的實例(除非添加@Builder到不返回自己類型的方法,否則總是如此),您可以使用@Builder(toBuilder = true)在類中生成實例方法調用toBuilder(); 它會創建一個以該實例的所有值開頭的新構建器。您可以將@Builder.ObtainVia注釋放在參數(如果是構造函數或方法)或字段(如果@Builder是類型)上,以指示從該實例獲取該字段/參數的值的替代方法。例如,您可以指定要調用的方法:@Builder.ObtainVia(method = "calculateFoo")

構建器類的名稱是*Foobar*Builder,其中Foobar目標返回類型的簡化,標題框形式- 即@Builder構造函數和類型的類型名稱,以及@Builderon方法的返回類型的名稱。例如,如果@Builder應用於名為的類com.yoyodyne.FancyList<T>,則構建器名稱將為FancyListBuilder<T>。如果@Builder應用於返回的方法,void則將命名構建器VoidBuilder

構建器的可配置方面是:

  • 生成器的類名(默認:返回類型+“生成器”)
  • 版本()方法的名稱(默認:"build"
  • 生成器()方法的名稱(默認:"builder"
  • 如果你想toBuilder()(默認:否)

所有選項均從其默認值更改的示例用法:
@Builder(builderClassName = "HelloWorldBuilder", buildMethodName = "execute", builderMethodName = "helloWorld", toBuilder = true)

@Builder.Default

如果在構建會話期間從未設置某個字段/參數,則它始終為0 / null/ false。如果您已經放置@Builder了一個類(而不是方法或構造函數),則可以直接在該字段上指定默認值,並使用以下內容對該字段進行注釋@Builder.Default
@Builder.Default private final long created = System.currentTimeMillis();

@Singular

通過使用注釋注釋其中一個參數(如果使用方法或構造函數進行注釋@Builder)或字段(如果使用注釋類@Builder@Singular,lombok將該構建器節點視為集合,並生成2個“加法器”方法而不是“ setter'方法。一個向集合添加單個元素,另一個將另一個集合的所有元素添加到集合中。將不生成僅設置集合(替換已添加的任何內容)的setter。還生成了“清晰”方法。這些“單一”構建器非常復雜,以保證以下屬性:

  • 調用時build(),生成的集合將是不可變的。
  • 在調用之后調用“adder”方法之一或“clear”方法build()不會修改任何已生成的對象,並且如果build()稍后再次調用,則會生成自生成構建器以來添加了所有元素的另一個集合。
  • 生成的集合將被壓縮到最小的可行格式,同時保持高效。

@Singular只能應用於lombok已知的集合類型。目前,支持的類型是:

  • java.util
    • IterableCollectionListArrayList在一般情況下由壓縮的不可修改的支持)。
    • SetSortedSetNavigableSet(由一個聰明的大小不可修改HashSetTreeSet在一般情況下支持)。
    • MapSortedMapNavigableMap(由一個聰明的大小不可修改HashMapTreeMap在一般情況下支持)。
  • 番石榴com.google.common.collect
    • ImmutableCollectionImmutableList(由構建器功能支持ImmutableList)。
    • ImmutableSetImmutableSortedSet(由這些類型的構建器功能支持)。
    • ImmutableMapImmutableBiMapImmutableSortedMap(由這些類型的構建器功能支持)。
    • ImmutableTable(由構建器功能支持ImmutableTable)。

如果您的標識符是用通用英語編寫的,則lombok假定其上的任何集合的名稱@Singular是英語復數,並將嘗試自動單獨化該名稱。如果可以,add-one方法將使用此名稱。例如,如果調用了您的集合statuses,則會自動調用add-one方法status。您還可以通過將單數形式作為參數傳遞給注釋來明確指定標識符的單數形式,如下所示:@Singular("axis") List<Line> axes;
如果lombok無法單獨標識您的標識符,或者它不明確,則lombok將生成錯誤並強制您明確指定單數名稱。

下面的代碼段沒有顯示lombok為@Singular字段/參數生成的內容,因為它相當復雜。您可以在此處查看代碼段。

With Jackson

您可以自定義構建器類的自定義部分,例如向構建器類添加另一個方法,或者在構建器類中注釋方法。Lombok將生成您不手動添加的所有內容,並將其放入此構建器類中。例如,如果您嘗試將jackson配置為對集合使用特定子類型,則可以編寫如下內容:

@Value @Builder
@JsonDeserialize(builder = JacksonExample.JacksonExampleBuilder.class)
public class JacksonExample { @Singular private List<Foo> foos; @JsonPOJOBuilder(withPrefix = "") public static class JacksonExampleBuilder implements JacksonExampleBuilderMeta { } private interface JacksonExampleBuilderMeta { @JsonDeserialize(contentAs = FooImpl.class) JacksonExampleBuilder foos(List<? extends Foo> foos) } } 

With Lombok

import lombok.Builder; import lombok.Singular; import java.util.Set; @Builder public class BuilderExample { @Builder.Default private long created = System.currentTimeMillis(); private String name; private int age; @Singular private Set<String> occupations; } 

Vanilla Java

import java.util.Set; public class BuilderExample { private long created; private String name; private int age; private Set<String> occupations; BuilderExample(String name, int age, Set<String> occupations) { this.name = name; this.age = age; this.occupations = occupations; } private static long $default$created() { return System.currentTimeMillis(); } public static BuilderExampleBuilder builder() { return new BuilderExampleBuilder(); } public static class BuilderExampleBuilder { private long created; private boolean created$set; private String name; private int age; private java.util.ArrayList<String> occupations; BuilderExampleBuilder() { } public BuilderExampleBuilder created(long created) { this.created = created; this.created$set = true; return this; } public BuilderExampleBuilder name(String name) { this.name = name; return this; } public BuilderExampleBuilder age(int age) { this.age = age; return this; } public BuilderExampleBuilder occupation(String occupation) { if (this.occupations == null) { this.occupations = new java.util.ArrayList<String>(); } this.occupations.add(occupation); return this; } public BuilderExampleBuilder occupations(Collection<? extends String> occupations) { if (this.occupations == null) { this.occupations = new java.util.ArrayList<String>(); } this.occupations.addAll(occupations); return this; } public BuilderExampleBuilder clearOccupations() { if (this.occupations != null) { this.occupations.clear(); } return this; } public BuilderExample build() { // complicated switch statement to produce a compact properly sized immutable set omitted. Set<String> occupations = ...; return new BuilderExample(created$set ? created : BuilderExample.$default$created(), name, age, occupations); } @java.lang.Override public String toString() { return "BuilderExample.BuilderExampleBuilder(created = " + this.created + ", name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")"; } } } 

Supported configuration keys:

lombok.builder.flagUsage = [warning | error] (default: not set)
lombok.singular.useGuava = [true | false] (default: false)
lombok.singular.auto = [true | false] (default: true)

Small print

@Singular支持java.util.NavigableMap/Set僅在您使用JDK1.8或更高版本進行編譯時才有效。

您無法手動提供@Singular節點的部分或全部部分; Lombok生成的代碼太復雜了。如果要手動控制(部分)與某個字段或參數關聯的構建器代碼,請不要@Singular手動使用和添加所需的所有內容。

排序集合(java.util中:SortedSetNavigableSetSortedMapNavigableMap,番石榴:ImmutableSortedSetImmutableSortedMap)要求該集合的類型參數有自然順序(實現java.util.Comparable)。無法Comparator在構建器中傳遞顯式內容。

如果目標集合來自包, An ArrayList用於將添加的元素存儲為@Singular標記字段的調用方法java.util即使集合是集合或映射也是如此。由於lombok確保生成的集合被壓縮,因此無論如何都必須構建集合或映射的新后備實例,並且ArrayList在構建過程中將數據存儲為將其存儲為映射或集合更有效。此行為不是外部可見的,是當前實現java.util配方的實現細節@Singular @Builder

隨着toBuilder = true應用到方法,注解的方法的任何類型的參數本身也必須在返回類型出現。

@Builder.Default刪除字段 上的初始化程序並將其存儲在靜態方法中,以確保在構建中指定值時,根本不會執行此初始化程序。這是否意味着初始化不能引用thissuper或任何非靜態成員。如果lombok為您生成構造函數,它還將使用初始化程序初始化此字段。

各種眾所周知的關於nullity的注釋會導致插入空檢查,並將其復制到構建器的'setter'方法的參數中。有關詳細信息,請參閱Getter / Setter文檔的小字體。



作者:eagle_king
鏈接:https://www.jianshu.com/p/5e42ecede166
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM