@Builder注解使用
作者:mmseoamin日期:2024-01-19

一、@Builder注解

资料来源: http://fendou.net.cn/index.php/a/369

https://blog.csdn.net/qq_39249094/article/details/120881578

  • 作用于类,将其变成建造者模式

    • 可以以链的形式调用

      • 初始化实例对象生成的对象是不可以变的,可以在创建对象的时候进行赋值(如果想改变的话需要在@Builder后面添加参数toBuilder=true)

        • 需要在原来的基础上修改可以加 set 方法,final 字段可以不需要初始化

          • 生成一个全参的构造函数

            1.0 Lombok坐标


            
               org.projectlombok
                lombok         
                0.10.2
            

            提供在设计数据实体时,对外保持private setter,而对属性的赋值采用Builder的方式,这种方式最优雅,也更符合封装的原则,不对外公开属性的写操作

            @Builder声明实体,表示可以进行Builder方式初始化

            @Value注解,表示只公开getter,对所有属性的setter都封闭,即private修饰,所以它不能和@Builder一起用

            1.1 注解使用


            @Builder
            @Getter
            @Data
            publicclassUserInfo {
                private  String  name;
                privateStringemail;
            ​
                @Override
                public String toString() {
                    return"UserInfo{"+
                            "name='"+name+'\''+
                            ", email='"+email+'\''+
                            '}';
                }
            ​
                public static void main(String[] args) {
                    UserInfo userInfo = UserInfo.builder().build();
                    System.out.println("userInfo---->"+userInfo);
            ​
                    UserInfo userInfo1 = UserInfo.builder()
                            .name("zzl")
                            .email("bgood@sina.com")
                            .build();
                    System.out.println("userInfo1---->"+userInfo1);
                }
            }

            @Builder注解使用,第1张

            1.2 注解的属性介绍


            1.2.1 toBuilder

            • 设置为 true 可以对这个对象进行拷贝生成新的对象,可以再修改,默认为 false

              怎么设置为true?

                @Builder(toBuilder = true)

              我们使用UserInfo.builder().build()创建出来之后,还可以修改对象的内容么(不使用set方法)?

              @Builder注解使用,第2张

              我们此时发现如果想对已经构建了的对象在修改的话,会出错,并找不到这个方法,我们只需要在类注解上添加@Builder(toBuilder = true)即可

                
              @Builder(toBuilder=true)
              @Getter
              public class UserInfo {}

              userInfo = userInfo.toBuilder()
                      .name("OK")
                      .email("zgood@sina.com")
                      .build();

              1.2.2 @Builder.Default 注解

              非 final 的字段可以有默认值

              @Builder.Default
              private String name ="刘亦菲";

              我们下面虽然没有对name赋值,但是输出时”name“依然会时"刘亦菲"

              UserInfo userInfo = UserInfo.builder().build();
              System.out.println("userInfo---->"+userInfo);

              final字段加不加Default都可以初始化成功,因为final字段如果第一次不是null的话,就不可修改(简单的来说,final字段有了初始值之后就不可更改)

              private final Integerage=18; 

              这两种写法都可以

              @Builder.Default
              private final Integer age;  

              1.2.3 buildMethodName

              指定创建实体类的方法名,默认值为 build

              当我们指定内部静态类的方法名为“test”的时候,发现下面已经开始报错了

              @Builder注解使用,第3张

              当我们把这里改成test之后便不会报错了

              @Builder注解使用,第4张

              1.2.4 builderMethodName

              指定创建内部静态类的方法名,默认值为 builder

              @Builder注解使用,第5张

              1.2.5 builderClassName

              指定内部静态的类名,默认值为 “”,默认创建的类名为 thisclassBuilder

              这个我不太懂,不知道怎么演示

              1.2.6 access

              设置 builderMethodName 的访问权限修饰符,默认为 public

              共有 PUBLIC、MODULE、PROTECTED、PACKAGE、PRIVATE,其中 MODULE 是 Java 9 的新特性

              access = AccessLevel.PUBLIC

              1.2.7 setterPrefix

              设置 setter 方法的前缀,默认为 “”

              1.3 处理添加无参构造函数报错时报错


              @Builder 会生成一个全参构造方法,因此就没有了无参构造方法,但当我们遇到需要无参构造方法时就会发生问题,这个时候手写或者加上 @NoArgsConstructor 都会报错

              @Builder注解使用,第6张

              1.3.1 处理方案1

              加上 @AllArgsConstructor

              @Builder注解使用,第7张

              1.3.2 处理方案2

              使用 @Builder 对一个 DTO 实现一个构造器,但是在做 Json 反序列化的时候发生错误,原因就是缺少无参公共的构造函数,而手动写一个无参构造函数的时候编译错误,就是和 @Builder 冲突

              虽然标准的 @Builder 没法是需要私有化构造函数的,但是在某些场景下我们需要对这种标准变形,这个时候 lombok 提供了 @Tolerate 实现对冲突的兼容

              使用@Tolerate注解

              我们手动添加一个无参构造函数,但是当运行之后就会出现错误

              @Builder注解使用,第8张

              但是当我们在无参构造函数上添加@Tolerate注解之后就可以正常运行

              @Builder注解使用,第9张

              1.4 @Builder内部


              • 创建一个名为 ThisClassBuilder 的内部静态类,并具有和实体类相同的属性(称为构建器)

                • 在构建器中:对于目标类中的所有的属性和未初始化的 final 字段,都会在构建器中创建对应属性

                  • 在构建器中:创建一个无参的 default 构造函数

                    • 在构建器中:实体类中的每个参数,都会对应创建类似于 setter 的方法,方法名与该参数名相同。 并且返回值是构建器本身(便于链式调用)

                      • 在构建器中:会创建一个 build 方法,调用 build 方法,就会根据设置的值进行创建实体对象

                        • 在构建器中:会生成一个 toString 方法

                          • 在实体类中:会创建一个 builder 方法,它的目的是用来创建构建器

                            @Builder
                            public class User {
                                private String username;
                                private String password;
                            }

                            public class User {
                                private String username;
                                private String password;
                            ​
                            ​
                                User(Stringusername, Stringpassword) {
                                    this.username=username;
                                    this.password=password;
                                }
                                
                            //  在实体类中会创建一个 builder 方法,它的目的是用来创建构建器
                                public static User.UserBuilder builder() {
                                    returnnewUser.UserBuilder();
                                }
                            //  构建器
                                public static class UserBuilder {
                                    //在构建器中:对于目标类中的所有的属性和未初始化的 final 字段,都会在构建器中创建对应属性
                                    private String username;
                                    private String password;
                                    
                                    //在构建器中:创建一个无参的 default 构造函数
                                    UserBuilder() {
                                    }
                            ​
                                    //在构建器中:实体类中的每个参数,都会对应创建类似于 setter 的方法,方法名与该参数名相同。 并且返回值是构建器本身(便于链式调用)        
                                    public User.UserBuilde rusername(Stringusername) {
                                        this.username=username;
                                        returnthis;
                                    }
                            ​
                                    public User.UserBuilderpassword(Stringpassword) {
                                        this.password=password;
                                        returnthis;
                                    }
                                    
                                    //在构建器中:会创建一个 build 方法,调用 build 方法,就会根据设置的值进行创建实体对象
                                    publicUserbuild() {
                                        return newUser(this.username, this.password);
                                    }
                                    
                                    //在构建器中:会生成一个 toString 方法 
                                    public String toString() {
                                        return"User.UserBuilder(username="+this.username+", password="+this.password+")";
                                    }
                                }
                            }