范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

还在手写Builder模式?试试Lombok中的Builder用法,太强了

  Builder 使用创建者模式又叫建造者模式。简单来说,就是一步步创建一个对象,它对用户屏蔽了里面构建的细节,但却可以精细地控制对象的构造过程。  基础使用
  @Builder 注释为你的类生成相对略微复杂的构建器API。@Builder 可以让你以下面显示的那样调用你的代码,来初始化你的实例对象: Student.builder()                .sno( "001" )                .sname( "admin" )                .sage( 18 )                .sphone( "110" )                .build();
  @Builder 可以放在类,构造函数或方法上。虽然放在类上和放在构造函数上这两种模式是最常见的用例,但@Builder 最容易用放在方法的用例来解释。 那么@Builder内部帮我们做了什么?创建一个名为 ThisClassBuilder 的内部静态类,并具有和实体类形同的属性(称为构建器)。 在构建器中:对于目标类中的所有的属性和未初始化的 final 字段,都会在构建器中创建对应属性。 在构建器中:创建一个无参的 default 构造函数。 在构建器中:对于实体类中的每个参数,都会对应创建类似于 setter 的方法,只不过方法名与该参数名相同。并且返回值是构建器本身(便于链式调用),如上例所示。 在构建器中:一个 build() 方法,调用此方法,就会根据设置的值进行创建实体对象。 在构建器中:同时也会生成一个 toString() 方法。 在实体类中:会创建一个 builder() 方法,它的目的是用来创建构建器。
  说这么多,不如让我们通过下面这个例子来理解  @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 + ")";         }     } } 组合用法
  @Builder中使用 @Singular 注释集合
  @Builder 也可以为集合类型的参数或字段生成一种特殊的方法。它采用修改列表中一个元素而不是整个列表的方式,可以是增加一个元素,也可以是删除一个元素。 Student.builder()                 .sno("001")                 .sname("admin")                 .sage(18)                 .sphone("110").sphone("112")                 .build();
  这样就可以轻松地将 List 字段中包含 2 个字符串。但是想要这样来操作集合,你需要使用@Singular 来注释字段或参数。23 种设计模式实战(很全)分享给你们。
  在使用 @Singular 注释注释一个集合字段(使用@Builder 注释类),lombok 会将该构建器节点视为一个集合,并生成两个adder 方法而不是setter 方法。 一个向集合添加单个元素  一个将另一个集合的所有元素添加到集合中
  将不生成仅设置集合(替换已添加的任何内容)的 setter。还生成了 clear 方法。这些 singular 构建器相对而言是有些复杂的,主要是来保证以下特性:  在调用 build() 时,生成的集合将是不可变的。 在调用 build() 之后调用其中一个adder 方法或clear 方法不会修改任何已经生成的对象。如果集合修改之后,再调用build() ,则会创建一个基于上一个对象创建的对象实体。 生成的集合将被压缩到最小的可行格式,同时保持高效。
  @Singular 只能应用于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<? extends String> 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 + ")";         }     } }
  其实,lombok 的创作者还是很用心的, 在进行build() 来创建实例对象时, 并没有直接使用Collections.unmodifiableList(Collection) 此方法来创建实例,而是分为三种情况。 第一种,当集合中没有元素时,创建一个空间 list  第二种情况,当集合中存在一个元素时,创建一个不可变的单元素 list  第三种情况,根据当前集合的元素数量创建对应合适大小的 list
  当然我们看编译生成的代码,创建了三个关于集合操作的方法:  hobby(String hobby) :向集合中添加一个元素 hobbies(Collection<? extends String> hobbies) :添加一个集合所有的元素 clearHobbies() :清空当前集合数据
  @Singular 注解配置 value 属性
  Java核心技术  专注分享Java核心技术干货,包括Java多线程、IO、JVM、Spring Boot、Spring Cloud、IntelliJ IDEA、Dubbo、Zookeeper、Redis、架构、微服务、消息队列、Git、面试题、最新动态等。15篇原创内容
  公众号
  我们先来看看 @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);     } }
  说明,当我们使用了注解属性 value 之后,我们在使用添加集合元素时的方法会发生相应的改变。但是,同时生成的添加整个集合的方法名发生改变了吗?我们再来看看编译后的代码: / 编译后: public class User {     // 省略部分代码,只看关键部分     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<? extends String> 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;         }     } }
  可以看到,只有添加一个元素的方法名发生了改变。 最新面试题整理好了,点击Java面试库小程序在线刷题。
  @Builder.Default 的使用
  比如有这样一个实体类:  @Builder @ToString public class User {     @Builder.Default     private final String id = UUID.randomUUID().toString();     private String username;     private String password;     @Builder.Default     private long insertTime = System.currentTimeMillis(); }
  在类中我在 id 和insertTime 上都添加注解@Builder.Default ,当我在使用这个实体对象时,我就不需要在为这两个字段进行初始化值,如下面这样: public class BuilderTest {     public static void main(String[] args) {         User user = User.builder()                 .password("admin")                 .username("admin")                 .build();         System.out.println(user);     } } // 输出内容: User(id=416219e1-bc64-43fd-b2c3-9f8dc109c2e8, username=admin, password=admin, insertTime=1546869309868)
  lombok 在实例化对象时就为我们初始化了这两个字段值。
  当然,你如果再对这两个字段进行设置置的话,那么默认定义的值将会被覆盖掉,如下面这样:  public class BuilderTest {     public static void main(String[] args) {         User user = User.builder()                 .id("admin")                 .password("admin")                 .username("admin")                 .build();         System.out.println(user);     } } // 输出内容 User(id=admin, username=admin, password=admin, insertTime=1546869642151)
  @Builder 详细配置
  下面我们再来详细看看 @Builder 这个注解类地详细实现: @Target({TYPE, METHOD, CONSTRUCTOR}) @Retention(SOURCE) public @interface Builder {     // 如果@Builder注解在类上,可以使用 @Builder.Default指定初始化表达式     @Target(FIELD)     @Retention(SOURCE)     public @interface Default {}     // 指定实体类中创建 Builder 的方法的名称,默认为: builder (个人觉得没必要修改)     String builderMethodName() default "builder";     // 指定 Builder 中用来构件实体类的方法的名称,默认为:build (个人觉得没必要修改)     String buildMethodName() default "build";     // 指定创建的建造者类的名称,默认为:实体类名+Builder     String builderClassName() default "";     // 使用toBuilder可以实现以一个实例为基础继续创建一个对象。(也就是重用原来对象的值)     boolean toBuilder() default false;          @Target({FIELD, PARAMETER})     @Retention(SOURCE)     public @interface ObtainVia {         // 告诉lombok使用表达式获取值         String field() default "";         // 告诉lombok使用表达式获取值         String method() default "";           boolean isStatic() default false;     } }
  以上注解属性,我只测试一个比较常用的 toBuilder ,因为我们在对实体对象进行操作时,往往会存在对某些实体对象的某个字段进行二次赋值,这个时候就会用到这一属性。最新面试题整理好了,点击Java面试库小程序在线刷题。
  但是,这会创建一个新的对象,而不是原来的对象,原来的对象属性是不可变的,除非你自己想要给这个实体类再添加上 @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();         // 验证user2是否是基于user1的现有属性创建的         System.out.println(user2);         // 验证对象是否是同一对象         System.out.println(user1 == user2);     } } // 输出内容 User(username=admin, password=admin) User(username=admin2, password=admin) false
  @Builder 全局配置  # 是否禁止使用@Builder lombok.builder.flagUsage = [warning | error] (default: not set) # 是否使用Guaua lombok.singular.useGuava = [true | false] (default: false) # 是否自动使用singular,默认是使用 lombok.singular.auto = [true | false] (default: true)
  总的来说 @Builder 还是很好用的。

中国颁布禁诉令法案,欧盟不满并告上世贸要求撤销,中方回应据联合早报2月19日报道,欧盟以中国限制欧洲企业的专利诉讼,阻止国际公司在外国法院起诉中国公司为由,将中国告上世贸组织,意图逼迫中方撤销与之相关的禁诉令法案。欧盟官员还威胁称,如果互联网典型案例(一)侵犯著作权罪案件来源最高人民法院转自深圳市罗湖区人民法院特别提示凡本号注明来源或转自的作品均转载自媒体,版权归原作者及原出处所有。所分享内容为作者个人观点,仅供读者学习参考,不代表本号观点近年来,麒麟9000L即将量产?华为新款Mate40EPro解决5G卡脖子问题由于美方的制裁,华为海思麒麟芯片用一颗少一颗,5G射频周边芯片的采购也出现了问题,这才导致2021年华为新机全面滑落到4G时代,一代机皇Mate40衍生出了包括Mate40EMat小米创始团队成员离职原因成谜据悉,小米创始团队成员,原小米技术委员会副主席兼秘书长李伟新离职。李伟星是小米的十二号员工,2010年4月6号小米公司成立。当天,与雷军一起喝小米粥的十三人中,李伟星就在此列。他早立讯精密造车?果链公司加速布局新能源汽车21世纪经济报道记者倪雨晴深圳报道智能电动车赛道又迎来一位重量级选手,目前近3000亿市值的立讯精密决定入场。在2月13日的一场调研会议上,立讯精密董事长总经理王来春谈道我们认为S果链不如新能源香?立讯精密豪掷100亿元携手奇瑞跨界造车本报记者谢岚见习记者李雯珊昔日备受市场青睐的苹果电子产业链板块因为业务环境的变化,似乎光环不再,纷纷转型。前有长盈精密大力布局动力电池结构件,后有蓝思科技开辟光伏新战场,如今立讯精78亿主力资金近三日撤出区块链概念股证券时报数据宝统计,近三日上证指数上涨1。14,A股成交金额较前三日下降8。95,主力资金净流出最多的概念为区块链,该概念所属个股共有228只,其中主力资金净流出前列的个股是省广集硬科技投向标东数西算工程全面启动多家科创板公司披露业绩快报科创板日报(上海,王梦雅)讯,本周,硬科技领域周报包括习近平加强国家安全等重要领域立法加快数字经济等领域立法步伐国常会推进制造业强链补链加快新型基础设施等建设多家科创板公司披露20网约车市场将再次洗牌据官方统计,一月份按订单合规率(指驾驶员和车辆均获得许可的订单量占比)从高到低的分别是享道出行妥妥E行如祺出行阳光出行携华出行T3出行及时用车蓝道出行神州专车招招出行首汽约车曹操出29岁程序员的删库跑路,被判10个月MySQL有望占据市场第一129岁程序员的删库跑路,被判10个月上海市杨浦区人民法院消息,一名29岁的程序员录某未经公司许可,在离职当天,私自将即将上线的京东到家平台系统代码全部删除,构成破坏计算机信息系统云计算板块中受机构关注度较高的龙头股1恒生电子现价53。49元,市值781。8亿,评级机构数38家分析优秀的金融科技公司,多个金融软件的市场占有率居全国前列,短线来看还没有企稳2用友网络现价32。19元,市值1106
SmartToolsPro今天推荐一款全是实用功能的安卓手机端app,它能解决N多生活中遇到的麻烦,堪称全能级!软件名为SmartToolsPro,它是一款强大的工具箱。它的功能涉及到生活中的方方面面,不仅iphone13支持无线充电吗iphone13支持反向充电吗iPhone13全系列是支持无线充电的,为用户带来更安全更方便的充电体验。那么iPhone13是否支持无线反向充电呢,在使用的时候我们怎么开启反向充电功能?不知道的小伙伴可以跟小编细数那些年科技厂商们的打脸设计机哥这几天刷友圈,诶,满世界都是新MacBookPro。不过,看着这新款的MacBook,机哥心里五味杂全兜兜转转这么多年,苹果终究是方向对了。饱受争议的TouchBar没了,SD睿思芯科创始人兼CEO谭章熹RISCEDGE睿思芯科创始人兼CEO谭章熹当芯片半导体遇上元宇宙,会碰撞出怎样的火花?12月9日下午,在钛媒体集团联合大兴产促中心国家新媒体产业基地共同主办的2021TEDGE全球创新大会上,睿三安光电VS京东方A两分钟看完他们说的两个LED企业4年的财务数据今天一起来看看他们从17年到20年的财务报表情况(单位)三安光电国内最大全色系超高亮度LED芯片生产企业,国内光电领域龙头京东方A全球领先的半导体显示技术产品与服务提供商1应收账款探讨全球科学趋势讲好湾区科技故事南方日报讯(记者卞德龙)12月11日,以探索未来共享科学为主题的2021年大湾区科学论坛将在广州开幕。日前,广州地标建筑广州塔为论坛亮灯,向来自全球的超百名与会院士专家表示欢迎。在SpringBoot统一处理全局异常注解的介绍ControllerAdviceControllerAdvice注解是Spring3。2中新增的注解,学名是Controller增强器,作用是给Controller控制器为啥现在很多人选择国产手机,而不是iPhone和三星了呢?原因简单而残酷,就一个字穷!穷肯定是穷呗。因为没钱穷我没选择国产,我用苹果,因为我需要ARkit2。0开发包,国产机是安卓系统,没有这玩意,ARCore还是远远赶不上苹果的ARKi5000元以上的手机,到底好在哪?好在配置,用料好在这种手机体现了现在科技的进步5K以上就完全属于旗舰机型了,所以题主问的就是高端机和中低端机的区别。高端机溢价其实比较大,因为它的价值已经不止体现在通讯工具上,更是华为高管Mate50已备好!5200mAh,HarmonyOS3板上钉钉在5G芯片遭遇困难之后,我们看到华为还是坚持做手机业务,不过可以明显看到的是,华为放在手机业务上的精力逐渐减少了。毕竟没有5G销量上就得不到保证,这种情况下华为把更多精力放在通讯系华为鸿蒙HarmonyOS5G新机入网信息公布,最高1TB存储IT之家12月8日消息,此前一款型号为NOHAN50的华为鸿蒙HarmonyOS5G新机获得入网许可。现在,该机的入网信息已经公布。根据公布的信息,这款5G新机拥有黑白两种配色,搭