<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          詳解 Lombok 中的 @Builder 用法!

          共 4494字,需瀏覽 9分鐘

           ·

          2022-01-04 15:02

          點(diǎn)擊下方“IT牧場”,選擇“設(shè)為星標(biāo)”

          來源 |?cnblogs.com/ajing2018/p/14281700.html

          01、詳解Lombok中的@Builder用法
          02、基礎(chǔ)使用
          03、那么@Builder內(nèi)部幫我們做了什么?
          04、組合用法

          01、詳解Lombok中的@Builder用法

          Builder?使用創(chuàng)建者模式又叫建造者模式。簡單來說,就是一步步創(chuàng)建一個(gè)對象,它對用戶屏蔽了里面構(gòu)建的細(xì)節(jié),但卻可以精細(xì)地控制對象的構(gòu)造過程。

          02、基礎(chǔ)使用

          @Builder注釋為你的類生成相對略微復(fù)雜的構(gòu)建器API。@Builder可以讓你以下面顯示的那樣調(diào)用你的代碼,來初始化你的實(shí)例對象:

          Student.builder()
          ???????????????.sno(?"001"?)
          ???????????????.sname(?"admin"?)
          ???????????????.sage(?18?)
          ???????????????.sphone(?"110"?)
          ???????????????.build();

          @Builder可以放在類,構(gòu)造函數(shù)或方法上。雖然放在類上和放在構(gòu)造函數(shù)上這兩種模式是最常見的用例,但@Builder最容易用放在方法的用例來解釋。

          03、那么@Builder內(nèi)部幫我們做了什么?

          1. 創(chuàng)建一個(gè)名為ThisClassBuilder的內(nèi)部靜態(tài)類,并具有和實(shí)體類形同的屬性(稱為構(gòu)建器)。
          2. 在構(gòu)建器中:對于目標(biāo)類中的所有的屬性和未初始化的final字段,都會在構(gòu)建器中創(chuàng)建對應(yīng)屬性。
          3. 在構(gòu)建器中:創(chuàng)建一個(gè)無參的default構(gòu)造函數(shù)。
          4. 在構(gòu)建器中:對于實(shí)體類中的每個(gè)參數(shù),都會對應(yīng)創(chuàng)建類似于setter的方法,只不過方法名與該參數(shù)名相同。并且返回值是構(gòu)建器本身(便于鏈?zhǔn)秸{(diào)用),如上例所示。
          5. 在構(gòu)建器中:一個(gè)build()方法,調(diào)用此方法,就會根據(jù)設(shè)置的值進(jìn)行創(chuàng)建實(shí)體對象。
          6. 在構(gòu)建器中:同時(shí)也會生成一個(gè)toString()方法。
          7. 在實(shí)體類中:會創(chuàng)建一個(gè)builder()方法,它的目的是用來創(chuàng)建構(gòu)建器。

          說這么多,不如讓我們通過下面這個(gè)例子來理解

          @Builder
          public?class?User?{
          ????private?final?Integer?code?=?200;
          ????private?String?username;
          ????private?String?password;
          }
          ?
          //?編譯后:
          public?class?User?{
          ????private?String?username;
          ????private?String?password;
          ????User(String?username,?String?password)?{
          ????????this.username?=?username;?this.password?=?password;
          ????}
          ????public?static?User.UserBuilder?builder()?{
          ????????return?new?User.UserBuilder();
          ????}
          ?
          ????public?static?class?UserBuilder?{
          ????????private?String?username;
          ????????private?String?password;
          ????????UserBuilder()?{}
          ?
          ????????public?User.UserBuilder?username(String?username)?{
          ????????????this.username?=?username;
          ????????????return?this;
          ????????}
          ????????public?User.UserBuilder?password(String?password)?{
          ????????????this.password?=?password;
          ????????????return?this;
          ????????}
          ????????public?User?build()?{
          ????????????return?new?User(this.username,?this.password);
          ????????}
          ????????public?String?toString()?{
          ????????????return?"User.UserBuilder(username="?+?this.username?+?",?password="?+?this.password?+?")";
          ????????}
          ????}
          }

          04、組合用法

          1. @Builder中使用 @Singular 注釋集合

          @Builder也可以為集合類型的參數(shù)或字段生成一種特殊的方法。它采用修改列表中一個(gè)元素而不是整個(gè)列表的方式,可以是增加一個(gè)元素,也可以是刪除一個(gè)元素。

          Student.builder()
          ????????????????.sno(?"001"?)
          ????????????????.sname(?"admin"?)
          ????????????????.sage(?18?)
          ????????????????.sphone(?"110"?).sphone(?"112"?)
          ????????????????.build();

          這樣就可以輕松地將List字段中包含2個(gè)字符串。但是想要這樣來操作集合,你需要使用@Singular來注釋字段或參數(shù)。

          在使用@Singular注釋注釋一個(gè)集合字段(使用@Builder注釋類),lombok會將該構(gòu)建器節(jié)點(diǎn)視為一個(gè)集合,并生成兩個(gè)adder方法而不是setter方法。

          • 一個(gè)向集合添加單個(gè)元素
          • 一個(gè)將另一個(gè)集合的所有元素添加到集合中

          將不生成僅設(shè)置集合(替換已添加的任何內(nèi)容)的setter。還生成了clear方法。這些singular構(gòu)建器相對而言是有些復(fù)雜的,主要是來保證以下特性:

          1. 在調(diào)用build()時(shí),生成的集合將是不可變的。
          2. 在調(diào)用build()之后調(diào)用其中一個(gè)adder方法或clear方法不會修改任何已經(jīng)生成的對象。如果對集合修改之后,再調(diào)用build(),則會創(chuàng)建一個(gè)基于上一個(gè)對象創(chuàng)建的對象實(shí)體。
          3. 生成的集合將被壓縮到最小的可行格式,同時(shí)保持高效。

          @Singular只能應(yīng)用于lombok已知的集合類型。目前,支持的類型有:

          java.util:

          • Iterable,?Collection, 和List?(一般情況下,由壓縮的不可修改的ArrayList支持).
          • Set,?SortedSet, and?NavigableSet?(一般情況下,生成可變大小不可修改的HashSet或者TreeSet).
          • Map,?SortedMap, and?NavigableMap?(一般情況下,生成可變大小不可修改的HashMap或者TreeMap).
          Guava’s?com.google.common.collect:
          • ImmutableCollection?and?ImmutableList
          • ImmutableSet?and?ImmutableSortedSet
          • ImmutableMap,?ImmutableBiMap, and?ImmutableSortedMap
          • ImmutableTable

          來看看使用了@Singular注解之后的編譯情況:

          @Builder
          public?class?User?{
          ????private?final?Integer?id;
          ????private?final?String?zipCode?=?"123456";
          ????private?String?username;
          ????private?String?password;
          ????@Singular
          ????private?List?hobbies;
          }
          ?
          //?編譯后:
          public?class?User?{
          ????private?final?Integer?id;
          ????private?final?String?zipCode?=?"123456";
          ????private?String?username;
          ????private?String?password;
          ????private?List?hobbies;
          ????User(Integer?id,?String?username,?String?password,?List?hobbies)?{
          ????????this.id?=?id;?this.username?=?username;
          ????????this.password?=?password;?this.hobbies?=?hobbies;
          ????}
          ?
          ????public?static?User.UserBuilder?builder()?{return?new?User.UserBuilder();}
          ?
          ????public?static?class?UserBuilder?{
          ????????private?Integer?id;
          ????????private?String?username;
          ????????private?String?password;
          ????????private?ArrayList?hobbies;
          ????????UserBuilder()?{}
          ????????public?User.UserBuilder?id(Integer?id)?{?this.id?=?id;?return?this;?}
          ????????public?User.UserBuilder?username(String?username)?{?this.username?=?username;?return?this;?}
          ????????public?User.UserBuilder?password(String?password)?{?this.password?=?password;?return?this;?}
          ?
          ????????public?User.UserBuilder?hobby(String?hobby)?{
          ????????????if?(this.hobbies?==?null)?{
          ????????????????this.hobbies?=?new?ArrayList();
          ????????????}
          ????????????this.hobbies.add(hobby);
          ????????????return?this;
          ????????}
          ?
          ????????public?User.UserBuilder?hobbies(Collection?hobbies)?{
          ????????????if?(this.hobbies?==?null)?{
          ????????????????this.hobbies?=?new?ArrayList();
          ????????????}
          ????????????this.hobbies.addAll(hobbies);
          ????????????return?this;
          ????????}
          ?
          ????????public?User.UserBuilder?clearHobbies()?{
          ????????????if?(this.hobbies?!=?null)?{
          ????????????????this.hobbies.clear();
          ????????????}
          ????????????return?this;
          ????????}
          ?
          ????????public?User?build()?{
          ????????????List?hobbies;
          ????????????switch(this.hobbies?==?null???0?:?this.hobbies.size())?{
          ????????????case?0:
          ????????????????hobbies?=?Collections.emptyList();
          ????????????????break;
          ????????????case?1:
          ????????????????hobbies?=?Collections.singletonList(this.hobbies.get(0));
          ????????????????break;
          ????????????default:
          ????????????????hobbies?=?Collections.unmodifiableList(new?ArrayList(this.hobbies));
          ????????????}
          ????????????return?new?User(this.id,?this.username,?this.password,?hobbies);
          ????????}
          ????????public?String?toString()?{
          ????????????return?"User.UserBuilder(id="?+?this.id?+?",?username="?+?this.username?+?",?password="?+?this.password?+?",?hobbies="?+?this.hobbies?+?")";
          ????????}
          ????}
          }

          其實(shí),lombok的創(chuàng)作者還是很用心的,在進(jìn)行build()來創(chuàng)建實(shí)例對象時(shí), 并沒有直接使用Collections.unmodifiableList(Collection)此方法來床架實(shí)例,而是分為三種情況。

          • 第一種,當(dāng)集合中沒有元素時(shí),創(chuàng)建一個(gè)空list
          • 第二種情況,當(dāng)集合中存在一個(gè)元素時(shí),創(chuàng)建一個(gè)不可變的單元素list
          • 第三種情況,根據(jù)當(dāng)前集合的元素?cái)?shù)量創(chuàng)建對應(yīng)合適大小的list

          當(dāng)然我們看編譯生成的代碼,創(chuàng)建了三個(gè)關(guān)于集合操作的方法:

          • hobby(String hobby):向集合中添加一個(gè)元素
          • hobbies(Collection hobbies):添加一個(gè)集合所有的元素
          • clearHobbies():清空當(dāng)前集合數(shù)據(jù)

          2. @Singular 注解配置value屬性

          我們先來看看 @Singular 注解的詳情:

          @Target({FIELD,?PARAMETER})
          @Retention(SOURCE)
          public?@interface?Singular?{
          ????//?修改添加集合元素的方法名
          ????String?value()?default?"";
          }
          • 測試如何使用注解屬性value
          @Builder
          public?class?User?{
          ????private?final?Integer?id;
          ????private?final?String?zipCode?=?"123456";
          ????private?String?username;
          ????private?String?password;
          ????@Singular(value?=?"testHobbies")
          ????private?List?hobbies;
          }
          ?
          //?測試類
          public?class?BuilderTest?{
          ????public?static?void?main(String[]?args)?{
          ????????User?user?=?User.builder()
          ????????????????.testHobbies("reading")
          ????????????????.testHobbies("eat")
          ????????????????.id(1)
          ????????????????.password("admin")
          ????????????????.username("admin")
          ????????????????.build();
          ????????System.out.println(user);
          ????}
          }

          說明,當(dāng)我們使用了注解屬性value之后,我們在使用添加集合元素時(shí)的方法名發(fā)生相應(yīng)的改變。但是,同時(shí)生成的添加整個(gè)集合的方法名發(fā)生改變了嗎?我們再來看看編譯后的代碼:

          /?編譯后:
          public?class?User?{
          ????//?省略部分代碼,只看關(guān)鍵部分
          ????public?static?class?UserBuilder?{
          ????????public?User.UserBuilder?testHobbies(String?testHobbies)?{
          ????????????if?(this.hobbies?==?null)?{
          ????????????????this.hobbies?=?new?ArrayList();
          ????????????}
          ????????????this.hobbies.add(testHobbies);
          ????????????return?this;
          ????????}
          ?
          ????????public?User.UserBuilder?hobbies(Collection?hobbies)?{
          ????????????if?(this.hobbies?==?null)?{
          ????????????????this.hobbies?=?new?ArrayList();
          ????????????}
          ????????????this.hobbies.addAll(hobbies);
          ????????????return?this;
          ????????}
          ????????
          ????????public?User.UserBuilder?clearHobbies()?{
          ????????????if?(this.hobbies?!=?null)?{
          ????????????????this.hobbies.clear();
          ????????????}
          ????????????return?this;
          ????????}
          ????}
          }

          可以看到,只有添加一個(gè)元素的方法名發(fā)生了改變。

          3. @Builder.Default 的使用

          比如有這樣一個(gè)實(shí)體類:

          @Builder
          @ToString
          public?class?User?{
          [email protected]
          ????private?final?String?id?=?UUID.randomUUID().toString();
          ????private?String?username;
          ????private?String?password;
          [email protected]
          ????private?long?insertTime?=?System.currentTimeMillis();
          }

          在類中我在idinsertTime上都添加注解@Builder.Default,當(dāng)我在使用這個(gè)實(shí)體對象時(shí),我就不需要在為這兩個(gè)字段進(jìn)行初始化值,如下面這樣:

          public?class?BuilderTest?{
          ????public?static?void?main(String[]?args)?{
          ????????User?user?=?User.builder()
          ????????????????.password("admin")
          ????????????????.username("admin")
          ????????????????.build();
          ????????System.out.println(user);
          ????}
          }
          ?
          //?輸出內(nèi)容:
          User(id=416219e1-bc64-43fd-b2c3-9f8dc109c2e8,?username=admin,?password=admin,?insertTime=1546869309868)

          lombok在實(shí)例化對象時(shí)就為我們初始化了這兩個(gè)字段值。

          當(dāng)然,你如果再對這兩個(gè)字段進(jìn)行設(shè)值的話,那么默認(rèn)定義的值將會被覆蓋掉,如下面這樣:

          public?class?BuilderTest?{
          ????public?static?void?main(String[]?args)?{
          ????????User?user?=?User.builder()
          ????????????????.id("admin")
          ????????????????.password("admin")
          ????????????????.username("admin")
          ????????????????.build();
          ????????System.out.println(user);
          ????}
          }
          //?輸出內(nèi)容
          User(id=admin,?username=admin,?password=admin,?insertTime=1546869642151)

          4. @Builder?詳細(xì)配置

          下面我們再來詳細(xì)看看@Builder這個(gè)注解類地詳細(xì)實(shí)現(xiàn):

          @Target({TYPE,?METHOD,?CONSTRUCTOR})
          @Retention(SOURCE)
          public?@interface?Builder?{
          ????//?如果@Builder注解在類上,可以使用[email protected]指定初始化表達(dá)式
          ????@Target(FIELD)
          ????@Retention(SOURCE)
          ????public?@interface?Default?{}
          ????//?指定實(shí)體類中創(chuàng)建?Builder?的方法的名稱,默認(rèn)為:?builder?(個(gè)人覺得沒必要修改)
          ????String?builderMethodName()?default?"builder";
          ????//?指定 Builder 中用來構(gòu)件實(shí)體類的方法的名稱,默認(rèn)為:build (個(gè)人覺得沒必要修改)
          ????String?buildMethodName()?default?"build";
          ????//?指定創(chuàng)建的建造者類的名稱,默認(rèn)為:實(shí)體類名+Builder
          ????String?builderClassName()?default?"";
          ????//?使用toBuilder可以實(shí)現(xiàn)以一個(gè)實(shí)例為基礎(chǔ)繼續(xù)創(chuàng)建一個(gè)對象。(也就是重用原來對象的值)
          ????boolean?toBuilder()?default?false;
          ????
          ????@Target({FIELD,?PARAMETER})
          ????@Retention(SOURCE)
          ????public?@interface?ObtainVia?{
          ????????//?告訴lombok使用表達(dá)式獲取值
          ????????String?field()?default?"";
          ????????//?告訴lombok使用表達(dá)式獲取值
          ????????String?method()?default?"";
          ?
          ????????boolean?isStatic()?default?false;
          ????}
          }

          以上注解屬性,我只測試一個(gè)比較常用的toBuilder,因?yàn)槲覀冊趯?shí)體對象進(jìn)行操作時(shí),往往會存在對某些實(shí)體對象的某個(gè)字段進(jìn)行二次賦值,這個(gè)時(shí)候就會用到這一屬性。但是,這會創(chuàng)建一個(gè)新的對象,而不是原來的對象,原來的對象屬性是不可變的,除非你自己想要給這個(gè)實(shí)體類再添加上@Data或者@setter方法。下面就來測試一下:

          @Builder(toBuilder?=?true)
          @ToString
          public?class?User?{
          ????private?String?username;
          ????private?String?password;
          }
          //?測試類
          public?class?BuilderTest?{
          ????public?static?void?main(String[]?args)?{
          ????????User?user1?=?User.builder()
          ????????????????.password("admin")
          ????????????????.username("admin")
          ????????????????.build();
          ????????System.out.println(user1);
          ?
          ????????User?user2?=?user1.toBuilder().username("admin2").build();
          ????????//?驗(yàn)證user2是否是基于user1的現(xiàn)有屬性創(chuàng)建的
          ????????System.out.println(user2);
          ????????//?驗(yàn)證對象是否是同一對象
          ????????System.out.println(user1?==?user2);
          ????}
          }
          //?輸出內(nèi)容
          User(username=admin,?password=admin)
          User(username=admin2,?password=admin)
          false

          5. @Builder?全局配置

          #?是否禁止使用@Builder
          lombok.builder.flagUsage?=?[warning?|?error]?(default:?not?set)
          #?是否使用Guaua
          lombok.singular.useGuava?=?[true?|?false]?(default:?false)
          #?是否自動使用singular,默認(rèn)是使用
          lombok.singular.auto?=?[true?|?false]?(default:?true)
          • 總的來說@Builder還是很好用的。

          瀏覽 47
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日韩午夜欧美精品 | 91精品国产91久久久久 | 九九九综合 | 国产小视频在线播放 | 伊人网大片 |