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

详解Lombok中的Builder及SuperBuilder用法

  本篇文章详细介绍了Java中lombok的 @Builder 注解及 @SuperBuilder 注解的解析和使用,希望对大家的学习或工作有一定的参考借鉴价值。废话不多说,直接上干货。 @Builder
  Lombok 的@Builder 提供了一种非常有用的机制,无需编写样板代码即可使用构建者模式。 @Builder  可以放在类,构造函数或方法上。 基础用法
  先定义示例类 Question,类声明中用 @Builder 注解。// 定义 Quesstion, 使用@Builder注解 @Builder public class Question {     private Long id;     private String question; }
  用@Builder  注解的类,Lombok会帮我们做以下几个事情(参考下面的示例代码):定义一个名为 XXXBuilder(XXX为目标类) 的内部静态类,具有与静态方法(称为构建器)相同的类型参数。在构建器中:目标类的每个成员变量都有一个私有的非static非final字段。在构建器中:一个私有无参数构造函数。在构建器中:目标类的每个成员变量都有类似"setter"的方法:它与该成员变量具有相同的类型和相同的名称,返回构建器本身,以便可以链式调用。在构建器中:调用build() 方法,传入每个字段。 它返回与目标类类型相同的实例对象。在构建器中:一个合理的 toString() 实现。在目标类中:一个 builder() 静态方法,它创建构建器的一个新实例。public class Question {     private Long id;     private String question;      Question(Long id, String question) {         this.id = id;         this.question = question;     }      public static QuestionBuilder builder() {         return new QuestionBuilder();     }      public static class QuestionBuilder {         private Long id;         private String question;          QuestionBuilder() {         }          public QuestionBuilder id(Long id) {             this.id = id;             return this;         }          public QuestionBuilder question(String question) {             this.question = question;             return this;         }          public Question build() {             return new Question(this.id, this.question);         }          public String toString() {             return "Question.QuestionBuilder(id=" + this.id + ", question=" + this.question + ")";         }     }组合用法
  @Builder中使用 @Singular 注释集合。// 定义 Answer,使用 @Builder注解 @Builder public class Answer {     private Long id;     private String answer;      }  // 定义 Quesstion, 使用@Builder注解 @Builder public class Question {     private Long id;     private String question;      @Singular     private List answers;      // @Singular("answer")     // private List answerList; }
  在使用 @Singular  注释注释一个集合字段(使用 @Builder  注释类), lombok  会将该构建器节点视为一个集合,并生成两个 adder方法  ,而不是 setter  方法。 一个往集合添加单个元素; 一个将另一个集合的所有元素添加到集合中;
  除此之外,还生成了clear方法,用于清空集合。 public class Question {     private Long id;     private String question;     List answers;      Question(Long id, String question, List answers) {         this.id = id;         this.question = question;         this.answers = answers;     }      public static QuestionBuilder builder() {         return new QuestionBuilder();     }      public static class QuestionBuilder {         private Long id;         private String question;         private ArrayList answers;          QuestionBuilder() {         }          public QuestionBuilder id(Long id) {             this.id = id;             return this;         }          public QuestionBuilder question(String question) {             this.question = question;             return this;         }          public QuestionBuilder answer(Answer answer) {             if (this.answers == null) {                 this.answers = new ArrayList();             }              this.answers.add(answer);             return this;         }          public QuestionBuilder answers(Collection<? extends Answer> answers) {             if (answers == null) {                 throw new NullPointerException("answers cannot be null");             } else {                 if (this.answers == null) {                     this.answers = new ArrayList();                 }                  this.answers.addAll(answers);                 return this;             }         }          public QuestionBuilder clearAnswers() {             if (this.answers != null) {                 this.answers.clear();             }              return this;         }          public Question build() {             List answers;             switch (this.answers == null ? 0 : this.answers.size()) {                 case 0:                     answers = Collections.emptyList();                     break;                 case 1:                     answers = Collections.singletonList(this.answers.get(0));                     break;                 default:                     answers = Collections.unmodifiableList(new ArrayList(this.answers));             }              return new Question(this.id, this.question, answers);         }          public String toString() {             return "Question.QuestionBuilder(id=" + this.id + ", question=" + this.question + ", answers=" + this.answers + ")";         }     } }
  从上面代码块,可以看到 在集合字段增加了@Singular 注解后,构建器的 build() 方法会更复杂一些,主要是为了保证以下两点:在调用 build()  时,生成的集合将是不可变的。 在调用build()之后调用其中一个adder方法或clear方法不会修改任何已经生成的对象。如果对集合修改之后,再调用build(),则会创建一个基于上一个对象创建的对象实体。生成的集合将被压缩到最小的可行格式,同时保持高效。
  如果您的标识符是用普通英语编写的,lombok 会假定任何带有 @Singular 的集合的名称是英语复数,并将尝试自动将该名称单数化。 如果可能,add-one 方法将使用此名称。 例如,如果这里我们定义的集合为answers,那么 add-one 方法将自动称为 answer(Answer answer)。 您还可以在@Singular注解中显式指定标识符的单数形式,如上面代码块中被注释的部分:@Singular("answer") private List answerList;
  如果 lombok 无法将您的标识符单数化,或者它有歧义,lombok 将生成错误并强制您明确指定单数名称。
  @Builder.Default 的使用
  如果在构建会话期间从未设置某个字段/参数,则它始终为 0/null/false。 如果您将 @Builder 放在类上(而不是方法或构造函数),您可以直接在字段上指定默认值,并使用 @Builder.Default 注释该字段:@Builder public class Answer {     @Builder.Default     private final String id = UUID.randomUUID().toString();     private String answer; }
  @Builder(toBuilder=true)
  如果我们想要创建对象的副本或近似副本,我们可以将属性 toBuilder = true 添加到 @Builder 注释中:
  Lombok 会在目标类中新增一个 toBuilder() 方法。当调用 toBuilder() 方法时,它会返回一个新的构建器,该构建器使用调用它的实例的属性进行初始化:  public class Answer {     private final String id;     private String answer;      private static String $default$id() {         return UUID.randomUUID().toString();     }      Answer(String id, String answer) {         this.id = id;         this.answer = answer;     }      public static AnswerBuilder builder() {         return new AnswerBuilder();     }      public AnswerBuilder toBuilder() {         return (new AnswerBuilder()).id(this.id).answer(this.answer);     }      public static class AnswerBuilder {         private boolean id$set;         private String id$value;         private String answer;          AnswerBuilder() {         }          public AnswerBuilder id(String id) {             this.id$value = id;             this.id$set = true;             return this;         }          public AnswerBuilder answer(String answer) {             this.answer = answer;             return this;         }          public Answer build() {             String id$value = this.id$value;             if (!this.id$set) {                 id$value = Answer.$default$id();             }              return new Answer(id$value, this.answer);         }          public String toString() {             return "Answer.AnswerBuilder(id$value=" + this.id$value + ", answer=" + this.answer + ")";         }     } }@SuperBuilder
  @Builder 并不支持对父类成员属性的构造,为解决这个问题, @SuperBuilder 应运而生,算是  @Builder 的升级版。 @SuperBuilder在 lombok v1.18.2 中作为实验性功能引入。
  定义示例类 Event和其子类 QuestionEvent。@SuperBuilder public class Event {     String message; }  @SuperBuilder public class QuestionEvent extends Event { }
  用@SuperBuilder 注解的类,Lombok会帮我们做以下几个事情(参考下面的示例代码):@SuperBuilder 在以builder实例作为参数的类上生成一个protect类型的构造函数。此构造函数将新实例的字段设置为builder中的值。  为了确保类型安全,@SuperBuilder 为每个注解类生成两个内部构建器类,一个抽象类和一个具体类,名为 XXXBuilder 和 XXXBuilderImpl(其中 XXX 是注解类的名称)。  public class Event {     String message;      protected Event(EventBuilder<?, ?> b) {         this.message = b.message;     }      public static EventBuilder<?, ?> builder() {         return new EventBuilderImpl();     }      private static final class EventBuilderImpl extends EventBuilder {         private EventBuilderImpl() {         }          protected EventBuilderImpl self() {             return this;         }          public Event build() {             return new Event(this);         }     }      public abstract static class EventBuilder> {         private String message;          public EventBuilder() {         }          protected abstract B self();          public abstract C build();          public B message(String message) {             this.message = message;             return this.self();         }          public String toString() {             return "Event.EventBuilder(message=" + this.message + ")";         }     } }public class QuestionEvent extends Event {     protected QuestionEvent(QuestionEventBuilder<?, ?> b) {         super(b);     }      public static QuestionEventBuilder<?, ?> builder() {         return new QuestionEventBuilderImpl();     }      private static final class QuestionEventBuilderImpl extends QuestionEventBuilder {         private QuestionEventBuilderImpl() {         }          protected QuestionEventBuilderImpl self() {             return this;         }          public QuestionEvent build() {             return new QuestionEvent(this);         }     }      public abstract static class QuestionEventBuilder> extends Event.EventBuilder {         public QuestionEventBuilder() {         }          protected abstract B self();          public abstract C build();          public String toString() {             return "QuestionEvent.QuestionEventBuilder(super=" + super.toString() + ")";         }     } }为什么@Builder不能处理父类的成员变量,而@SuperBuilder可以?
  原因在于,在Java的抽象语法树设计上,每个类只包含了显式声明的变量而不包括父类的成员变量。Lombok针对@Builder注解的内部实现findAllFields  方法是从当前类的抽象语法树出发去找所有的成员变量,所以就只能找到当前类的成员变量,而访问不到父类的成员变量。
  @SuperBuilder注解的内部实现,在查找所有成员变量之前,先拿到了继承的父类的抽象语法树。 JCClassDecl td = (JCClassDecl) parent.get(); // 获取继承的父类的抽象语法树 JCTree extendsClause = Javac.getExtendsClause(td); JCExpression superclassBuilderClass = null; if (extendsClause instanceof JCTypeApply) {    // Remember the type arguments, because we need them for the extends clause of our abstract builder class.    superclassTypeParams = ((JCTypeApply) extendsClause).getTypeArguments();    // A class name with a generics type, e.g., "Superclass".    extendsClause = ((JCTypeApply) extendsClause).getType(); } if (extendsClause instanceof JCFieldAccess) {    Name superclassName = ((JCFieldAccess) extendsClause).getIdentifier();    String superclassBuilderClassName = superclassName.toString() + "Builder";    superclassBuilderClass = parent.getTreeMaker().Select((JCFieldAccess) extendsClause, parent.toName(superclassBuilderClassName)); } else if (extendsClause != null) {    String superclassBuilderClassName = extendsClause.toString() + "Builder";    superclassBuilderClass = chainDots(parent, extendsClause.toString(), superclassBuilderClassName); }注意点@SuperBuilder 与@Builder 不兼容,不能一起使用。  被 @SuperBuilder 注解的类,其父类也必须使用@SuperBuilder注解。

玩的是同一个英雄联盟,为何感觉敌我双方差距总是那么大呢?同玩的一个英雄联盟,为何敌我双方队友的差距这么大呢?真相太过于真实英雄联盟发展到现在已经运营了8年,依然是电脑端最火爆的游戏,也是陪伴了很多玩家青春的游戏只要玩过这个游戏的玩家,都有没有要退休,一想到收入锐减,心里就发慌的感觉?这个问题我比较有发言权。我就是本月退休的大型央企垄断行业的员工,虽然我的退休工资还没有最后核定出来,但也咨询过比我早退休几个月的同等条件下的同事。在职的情况下,是五险两金,交费比例为什么感觉国乒回国关于孙颖莎的报道比较多?感谢邀请!不管莎莎是输球,还是赢球,她的人气都很高,哪怕是大赛三连亚,她的热搜也是高于冠军陈梦王曼昱,出现这样的情况原因是什么呢?下面也来探讨一下第一,莎莎赢球都是关键战,给球迷留为什么感觉小县城的人口越来越少,房价却越来越贵?谁会在县城买房?目前农村已经没年轻人了,剩下的老人不可能去县城买房,反而县城的有办法的人陆续离开县城去大城市发展,现在的情况是县城的房子再便宜也没人买了俗话说没有不开张的油盐店,没有嫁不出去的丑姑游了黄山又游泰山感觉相同吗?相同的感觉只有爬山这一点相同。其余感受完全不同。我35年前去过泰山,19902005两次游过黄山。泰山,自然景色一般,虽然号称五岳独尊,但自然风光比华山差远了,比恒山衡山各有千秋,国产车品牌那么多,哪个在世界上知名度最高?国产汽车品牌世界知名度最高的可能是你不认识的品牌中国汽车品牌在海外知名度最高的是哪个呢?看到这个问题也许很多汽车爱好者就准备开始一场关于奇瑞力帆吉利长安长城等品牌的论战了,然而国际定增对股价有什么影响?1什么是定增?首先,在定向增发实施后,定增价格将对股价形成定增的全称是定向增发,即上市公司增发股票的时候不实行公开发行,而是向特定的少数投资人发行股票,也叫非公开发行。定增的两个关为什么(天天向上)越来越有内涵?谢邀!天天向上有内涵吗?从五兄弟解体之后,天天向上一路走下坡路,虽然后来找到大张伟王一博等人接替,可形式始终没有发生根本性改变。从当年巅峰的时候开始,天天向上就没有内涵这一说,只不lol各个大区的火热程度排名是怎样的?首先给大家分享一下截止到2019年英雄联盟各个服务器玩家数量,排在前十的分别为艾欧尼亚,德玛西亚,黑色玫瑰,比尔吉沃特,祖安,战争学院,诺克萨斯,班德尔城,弗雷尔卓德,无畏先锋。从有人说周琦超过易建联,那么令他成功因素是什么?谢谢邀请,咋听这个提问有点言过其实,但是你不能不说周琦确实在某些方面超过了易建联,但是他球商球技还是前一把火候。据统计,周琦在薪水身高臂展站立原地弹跳上略高于易建联,这也是不争的事国外有很多人用小米手机吗?这个问题问的咋这么可笑呢?这是明知故问呢?还是没什么话说了,小米手机世界销量第二,那他的手机在国外卖给谁了?外国人不用,难道手机不是人用的吗?国外有很多人用小米是真的,甚至比国内的
罗马俱乐部中国委员会召开工作会议,筹备2023国际生物多样性会议北京时间2023年2月14日下午,罗马俱乐部中国委员会(TheChinaAssociationfortheClubofRome)召开2023年二月工作会议。在主席乔根兰德斯(Jor永定区桥头乡织牢就业保障网紧贴重点群体心红网时刻张家界2月21日讯(通讯员卓东云)2月21日,永定区桥头乡召开2023年劳保站就业工作部署会,会议紧紧围绕保重点群体就业工作展开。会上指出,高校毕业生农民工特别是脱贫劳动力创造历史!徐汇小囡成首个站上世界杯领奖台的中国雪车运动员北京时间2月18日,在国际雪车联合会世界杯锡古尔达站女子单人雪车项目的比赛中,由徐汇培养输送的运动员应清,以两轮滑行1分47秒10的用时获得铜牌,不仅创造了个人最佳战绩,也创造历史日媒旅日熊猫香香给地区经济带来活力我们满心感激来源海外网大批游客在上野动物园门口等待参观香香(朝日电视台)海外网2月21日电旅日大熊猫香香21日早晨乘包机返回中国。日本经济新闻21日刊文表示,香香受到广大日本民众的喜爱,也给当亚马逊要求员工一周到岗工作3天亚马逊公司当地时间2月18日在官方博客宣布,将要求公司员工从今年5月1日起每周至少在办公室上班三天,少数销售和客户支持人员除外。亚马逊此前在2021年10月表示,由各个团队决定员工世界最大打桩船一航津桩完成首次施工作业2023。2。20云南天文台立体观测到太阳暗条纵横双向振荡近日,中国科学院云南天文台选址与日冕观测组在大振幅暗条振荡研究中获得新的观测结果,相关成果发表在皇家天文学会月刊上。暗条是后生元产业首个团体标准发布科拓生物参与制定工作中证网讯(记者潘宇静)2月21日,国内首个益生菌制品乳酸菌类后生元团体标准宣贯会在北京召开,这是我国后生元领域的第一个团体标准,该标准由中国生物发酵产业协会发布实施,科拓生物提出立工信部第五批专精特新小巨人企业培育工作启动视频加载中中证网声明凡本网注明来源中国证券报。中证网的所有作品,版权均属于中国证券报中证网,中国证券报。中证网与作品作者联合声明,任何组织未经中国证券报。中证网以及作者书面授权不得埃格努遭嫌弃!3大豪门抢一个强力接应,朱婷老东家被曝商谈失败本赛季各国女排联赛还没有完全结束,例如土超和意甲需要到五月份才能完成比赛任务。但是各支俱乐部已经在为下赛季的引援工作做准备,最令人关注的就是土超豪门瓦基弗看上了费内巴切的强力接应瓦南北朝时期,元嘉北伐损失惨重,奠定了北强南弱的格局南朝北朝不是单指一个朝代,而是一堆朝代的合称,南方非著名草根刘裕推翻了东晋,从此历经宋齐梁陈四个朝代,统称南朝。北方的鲜卑人拓跋焘,将五胡统一收拾起来,建立北魏,后裂成两半,各自发美国工厂投资35亿美元,宁德时代占股为0,宁德和福特的各自盘算最近看到一则报道,宁德时代和福特在美国合伙投资一个新的电池工厂,该工厂计划投资35亿美元,年产能36GWh,建成后可以供应40万辆电动汽车,这将给福特汽车的电动化转型提供支撑。但在