码迷,mamicode.com
首页 > 其他好文 > 详细

Lombok插件使用详解及原理

时间:2020-10-18 17:10:57      阅读:7      评论:0      收藏:0      [点我收藏+]

标签:类对象   abstract   bre   postfix   比较   匹配   配置   script   抛出异常   

1、Lombok简介   Lombok是一个插件,其主要用途是提供了简单的注解的形式来帮助我们简化消除一些必须有但显得很臃肿的 java 代码,提高编码效率,使代码更简洁。

  Lombok能以简单的注解形式来简化java代码,提高开发人员的开发效率。例如开发中经常需要写的javabean,都需要花时间去添加相应的getter/setter,也许还要去写构造器、equals等方法,而且需要维护,当属性多时会出现大量的getter/setter方法,这些显得很冗长也没有太多技术含量,一旦修改属性,就容易出现忘记修改对应方法的失误。

  Lombok能通过注解的方式,在编译时自动为属性生成构造器、getter/setter、equals、hashcode、toString方法。

2、Lombok插件安装   想要使用 Lombok,必须要安装一个 Lombok 插件,不然的话,ide 编辑器会无法识别 Lombok 的注解,报找不到方法的异常。

  以 idea 为例,直接在工具中搜索 Lombok 插件,然后安装它。安装完成后重启 idea 开发工具即可。

  

  接下来,我们需要在使用 Lombok 的项目中引入 Lombok 的 jar 包。Maven 的 pom.xml 中引入以下配置:

org.projectlombok lombok 1.18.10 provided 3、Lombok注解   3.1、变量相关   3.1.1、val和var   lombok帮助java低级版本拥有jdk10的特性(在lombok 0.10引入)。

  使用var作为任何局部变量声明的类型(即使在for语句中),该类型将从初始化表达式中推断出来(该类型推断中不涉及对变量的任何进一步赋值)。例如:

var x=10.0; 将推断double; var y=new arraylist(); 将推断Arraylist;   注意:

对于复合类型,推断出最常见的父类,而不是接口。例如,bool ? new HashSet() : new ArrayList()是一个带有复合类型的表达式.存在同样的父类:AbstractCollection,也实现了同样的接口:Serializable。最终推断的类型将是AbstractCollection,因为它是一个类,而Serializable是接口。 在不明确的情况下,例如当初始化表达式是null,将推断为java.lang.Object 这是一个注释类型,因为var x=10;将被解语法糖为@var int x=10; 注意:var 和 val 具有完全相同的语义,只是val变成@val   但是推荐使用val,因为idea具有val自带的postfix template:

//使用示例 public String example() { val example = new ArrayList(); example.add("Hello, World!"); val foo = example.get(0); return foo.toLowerCase(); }   3.1.2、NonNull   在方法参数上:Lombok将在方法/构造函数体的开头插入一个空检查,并将参数的名称作为消息引发一个NullPointerException。

  在字段上:任何为该字段赋值的生成方法也将生成这些空检查。

  例如:

public class DataExample { @NonNull private String name; }   编译后的class为:

public class DataExample { public DataExample(@NonNull String name) { if (name == null) throw new NullPointerException("name is marked non-null but is null"); this.name = name; }

public void setName(@NonNull String name) {
    if (name == null)
        throw new NullPointerException("name is marked non-null but is null");
    this.name = name;
}

}   3.2、实体类相关   3.2.1、@Getter、@Setter   取代实体类中的get和set方法:可以在任何字段上使用@Getter或@Setter,lombok会自动生成默认的getter / setter;如果在类上使用,则所有字段生成getter / setter。

  AccessLevel:可以通过AccessLevel重写访问级别。

  关于字段注释(lombok v1.12.0中的新功能):将字段上的javadoc复制到生成的getter和setter。

  关于方法命名:     getter:默认情况下方法名为:get+字段名以驼峰连接;如果是boolean类型则:is+字段名以驼峰连接。(Boolean类型是get开头)。不建议使用is开头的字段命名,会产生混淆:

    setter:setter不受boolean影响:set+字段名以驼峰连接。

  例如:

public class DataExample { @Setter(AccessLevel.PROTECTED) private String name; @Getter @Setter boolean flag; @Getter @Setter Boolean flagObj; }   编译后的class为:

public class DataExample {private String name; boolean flag; Boolean flagObj; protected void setName(String name)

public boolean isFlag() {
    return this.flag;
}

public void setFlag(boolean flag) {
    this.flag = flag;
}

public Boolean getFlagObj() {
    return this.flagObj;
}

public void setFlagObj(Boolean flagObj) {
    this.flagObj = flagObj;
}

}   特殊事项:

@Getter可用于枚举而@Setter不能 来自流行库的注释检查,例如javax.annotation.Nonnull,如果存在于字段上,导致生成的setter中会进行显式的空检查。 当与@Accessors注解一起使用会产生影响   3.2.2、@Accessors   使用在类或字段上,目的是修改getter和setter方法的内容(在lombok v0.11.0中作为实验特征引入)。

  功能:

fluent:如果为true,那么getter 和setter 生成的方法名没有前缀。此外,除非指定,否则chain将为true。 chain:如果为true,则生成的setter返回this而不是void。默认值:false prefix:如果存在,则字段必须以任何这些前缀为前缀。每个字段名称依次与列表中的每个前缀进行比较,如果找到匹配项,则会剥离前缀以创建字段的基本名称。在列表中包含一个空字符串是合法的它将始终匹配。对于字母的字符,前缀后面的字符不能是小写字母,即以p为前缀也不会匹配pepper,但是pEpper会被匹配上(并且意味着该字段的基本名称epper)。如果提供了前缀列表并且字段不以其中一个字段开头,则lombok将完全跳过该字段,并将生成警告   示例如下:

@Getter @Setter public class AccessorsExample { @Accessors(fluent = true) private int age = 10;

@Accessors(prefix = "f")
private String fName;

@Accessors(chain = true)
private String chainName;

}   编译后的class为:

public class AccessorsExample {

private int age = 10; private String fName; private String chainName;

public int age() { return this.age; }

public AccessorsExample age(int age) { this.age = age; return this; }

public String getName() { return this.fName; }

public void setName(String fName)

public AccessorsExample setChainName(String chainName) { this.chainName = chainName; return this; }

public String getChainName() { return this.chainName; } }   3.2.3、@AllArgsConstructor、RequiredArgsConstructor、@NoArgsConstructor   分别生成全参构造方法,带参构造,无参构造。

  @NoArgsConstructor : 生成一个没有参数的构造器。

  @AllArgsConstructor : 生成一个包含所有参数的构造器

  @RequiredArgsConstructor : 生成一个包含 "特定参数" 的构造器,特定参数指的是那些有加上 final 修饰词的变量们或者加了@NonNull注解的参数。如果指定staticName = "of"参数,还会生成一个返回类对象的静态工厂方法。

  如下例:

@RequiredArgsConstructor(staticName = "of") @AllArgsConstructor(access = AccessLevel.PROTECTED) public class ConstructorExample { private int x, y; @NonNull private T description; private final String finalString;

@NoArgsConstructor
public static class NoArgsExample {
    @NonNull private String field;
}

}   经过编译后,class文件反编译,实际的类文件等同于:

public class ConstructorExample { private int x; private int y; @NonNull private T description; private final String finalString;

private ConstructorExample(@NonNull T description, String finalString) {
    if (description == null)
        throw new NullPointerException("description is marked non-null but is null");
    this.description = description;
    this.finalString = finalString;
}

public static <T> ConstructorExample<T> of(@NonNull T description, String finalString) {
    return new ConstructorExample<>(description, finalString);
}

protected ConstructorExample(int x, int y, @NonNull T description, String finalString) {
    if (description == null)
        throw new NullPointerException("description is marked non-null but is null");
    this.x = x;
    this.y = y;
    this.description = description;
    this.finalString = finalString;
}

public static class NoArgsExample {
    @NonNull
    private String field;
}

}   这里注意一个 Java 的小坑,当我们没有指定构造器时,Java 编译器会帮我们自动生成一个没有任何参数的构造器给该类,但是如果我们自己写了构造器之后,Java 就不会自动帮我们补上那个无参数的构造器了,然而很多地方(像是 Spring Data JPA),会需要每个类都一定要有一个无参数的构造器,所以你在加上 @AllArgsConstructor 时,一定要补上 @NoArgsConstrcutor,不然会有各种坑等着你。

  3.2.4、@ToString   类使用@ToString注解,Lombok会生成一个toString()方法,默认情况下,会输出类名、所有属性(会按照属性定义顺序),用逗号来分割。通过将includeFieldNames参数设为true,就能明确的输出toString()属性。这一点是不是有点绕口,通过代码来看会更清晰些。

  使用Lombok的示例:

@ToString(exclude="id") public class ToStringExample { private static final int STATIC_VAR = 10; private String name; private Shape shape = new Square(5, 10); private String[] tags; private int id;

@ToString(callSuper=true, includeFieldNames=true)
public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
        this.width = width;
        this.height = height;
    }
}

}   经过编译后,class文件反编译,实际的类文件等同于:

public class ToStringExample {

private int id;
private static final int STATIC_VAR = 10;
private String name;
private Shape shape = new Square(5, 10);
private String[] tags;

public String toString() {
    return "ToStringExample(name=" + getName() + ", shape=" + this.shape + ", tags=" + Arrays.deepToString((Object[])this.tags) + ")";
}

public static class Square extends Shape {
    private final int width;
    private final int height;

    public Square(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public String toString() {
        return "ToStringExample.Square(super=" + super.toString() + ", width=" + this.width + ", height=" + this.height + ")";
    }
}

}   3.2.5、@EqualsAndHashCode   默认情况下,会使用所有非静态(non-static)和非瞬态(non-transient)属性来生成equals/canEqual和hasCode,也能通过exclude注解来排除一些属性。

  使用Lombok的示例:

@EqualsAndHashCode(exclude={"id", "shape"}) public class EqualsAndHashCodeExample { private transient int transientVar = 10; private String name; private double score; private Shape shape = new Square(5, 10); private String[] tags; private int id;

@EqualsAndHashCode(callSuper=true)
public static class Square extends Shape {
    private final int width, height;

    public Square(int width, int height) {
        this.width = width;
        this.height = height;
    }

    @Override
    public com.sun.javafx.geom.Shape impl_configShape() {
        return null;
    }
}

}   经过编译后,class文件反编译,实际的类文件等同于:

public class EqualsAndHashCodeExample {

private transient int transientVar = 10;
private int id;
private String name;
private double score;
private Shape shape = new Square(5, 10);
private String[] tags;


public int hashCode() {
    int PRIME = 59;
    result = 1;
    Object $name = getName();
    result = result * 59 + (($name == null) ? 43 : $name.hashCode());
    long $score = Double.doubleToLongBits(this.score);
    result = result * 59 + (int)($score >>> 32L ^ $score);
    return result * 59 + Arrays.deepHashCode((Object[])this.tags);
}

protected boolean canEqual(Object other) {
    return other instanceof EqualsAndHashCodeExample;
}

public boolean equals(Object o) {
    if (o == this)
        return true;
    if (!(o instanceof EqualsAndHashCodeExample))
        return false;
    EqualsAndHashCodeExample other = (EqualsAndHashCodeExample)o;
    if (!other.canEqual(this))
        return false;
    Object this$name = getName(), other$name = other.getName();
    return ((this$name == null) ? (other$name != null) : !this$name.equals(other$name)) ? 

         false : ((Double.compare(this.score, other.score) != 0) ? false : (!!Arrays.deepEquals((Object[])this.tags, (Object[])other.tags))); }

public static class Square extends Shape {
    private final int width;
    private final int height;

    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Square))
            return false;
        Square other = (Square)o;
        return !other.canEqual(this) ? false : (!super.equals(o) ? 

            false : ((this.width != other.width) ? false : (!(this.height != other.height)))); }

    protected boolean canEqual(Object other) {
        return other instanceof Square;
    }

    public int hashCode() {
        int PRIME = 59;
        result = super.hashCode();
        result = result * 59 + this.width;
        return result * 59 + this.height;
    }

    public Square(int width, int height) {
        this.width = width;
        this.height = height;
    }
}

}   3.2.6、@Data   作用在类上,相当于集成以下注解

@Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode   其独有属性配置:

staticConstructor 静态方法名:@Data(staticConstructor=“of”)通过新的方式来创建实例:Foo.of(5)   Lombok示例如下:

@Data public class DataExample { private final String name; @Setter(AccessLevel.PACKAGE) private int age; private double score; private String[] tags;

@ToString(includeFieldNames=true)
@Data(staticConstructor="of")
public static class Exercise<T> {
    private final String name;
    private final T value;
}

}   经过编译后,class文件反编译,实际的类文件等同于:

public class DataExample { private final String name; private int age; private double score; private String[] tags;

public DataExample(String name)

public String getName() { return this.name; }

void setAge(int age)

public int getAge() { return this.age; }

public void setScore(double score)

public double getScore() { return this.score; }

public String[] getTags() { return this.tags; }

public void setTags(String[] tags)

@Override public String toString() { return "DataExample(" + this.getName() + ", " + this.getAge() + ", " + this.getScore() + ", " + Arrays.deepToString(this.getTags()) + ")"; }

protected boolean canEqual(Object other) { return other instanceof DataExample; }

@Override public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof DataExample)) return false; DataExample other = (DataExample) o; if (!other.canEqual((Object)this)) return false; if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false; if (this.getAge() != other.getAge()) return false; if (Double.compare(this.getScore(), other.getScore()) != 0) return false; if (!Arrays.deepEquals(this.getTags(), other.getTags())) return false; return true; }

@Override public int hashCode() { final int PRIME = 59; int result = 1; final long temp1 = Double.doubleToLongBits(this.getScore()); result = (resultPRIME) + (this.getName() == null ? 43 : this.getName().hashCode()); result = (resultPRIME) + this.getAge(); result = (resultPRIME) + (int)(temp1 ^ (temp1 >>> 32)); result = (resultPRIME) + Arrays.deepHashCode(this.getTags()); return result; }

public static class Exercise { private final String name; private final T value;

private Exercise(String name, T value) {
  this.name = name;
  this.value = value;
}

public static <T> Exercise<T> of(String name, T value) {
  return new Exercise<T>(name, value);
}

public String getName() {
  return this.name;
}

public T getValue() {
  return this.value;
}

@Override public String toString() {
  return "Exercise(name=" + this.getName() + ", value=" + this.getValue() + ")";
}

protected boolean canEqual(Object other) {
  return other instanceof Exercise;
}

@Override public boolean equals(Object o) {
  if (o == this) return true;
  if (!(o instanceof Exercise)) return false;
  Exercise<?> other = (Exercise<?>) o;
  if (!other.canEqual((Object)this)) return false;
  if (this.getName() == null ? other.getValue() != null : !this.getName().equals(other.getName())) return false;
  if (this.getValue() == null ? other.getValue() != null : !this.getValue().equals(other.getValue())) return false;
  return true;
}

@Override public int hashCode() {
  final int PRIME = 59;
  int result = 1;
  result = (result*PRIME) + (this.getName() == null ? 43 : this.getName().hashCode());
  result = (result*PRIME) + (this.getValue() == null ? 43 : this.getValue().hashCode());
  return result;
}

} }   通常 @Data 会加在一个值可以被更新的对象上,像是日常使用的 DTO 们、或是 JPA 裡的 Entity 们,就很适合加上 @Data 注解,也就是 @Data for mutable class。

  3.2.7、@Value   也是整合包,但是他会把所有的变量都设成 final 的,其他的就跟 @Data 一样,等于同时加了以下注解:@ToString,@EqualsAndHashCode,@AllArgsConstructor,@FieldDefaults,@Getter。

  所有字段由private和final修饰,不会产生setter方法。类本身也是由final修饰。

  创建Lombok示例如下:

@Value public class ValueExample { String name; @NonFinal int age; double score; protected String[] tags;

@ToString(includeFieldNames=true)
@Value(staticConstructor="of")
public static class Exercise<T> {
    String name;
    T value;
}

}   经过编译后,class文件反编译,实际的类文件等同于:

public final class ValueExample { private final String name;

private int age;

private final double score;

protected final String[] tags;

public ValueExample(String name, int age, double score, String[] tags) {
    this.name = name;
    this.age = age;
    this.score = score;
    this.tags = tags;
}

public boolean equals(Object o) {
    if (o == this)
        return true;
    if (!(o instanceof ValueExample))
        return false;
    ValueExample other = (ValueExample)o;
    Object this$name = getName(), other$name = other.getName();
    return ((this$name == null) ? (other$name != null) : !this$name.equals(other$name)) ? false : ((getAge() != other.getAge()) ? false : ((Double.compare(getScore(), other.getScore()) != 0) ? false : (!!Arrays.deepEquals((Object[])getTags(), (Object[])other.getTags()))));
}

public int hashCode() {
    int PRIME = 59;
    result = 1;    //不知道为什么反编译class会是这样的写法
    Object $name = getName();
    result = result * 59 + (($name == null) ? 43 : $name.hashCode());
    result = result * 59 + getAge();
    long $score = Double.doubleToLongBits(getScore());
    result = result * 59 + (int)($score >>> 32L ^ $score);
    return result * 59 + Arrays.deepHashCode((Object[])getTags());
}

public String toString() {
    return "ValueExample(name=" + getName() + ", age=" + getAge() + ", score=" + getScore() + ", tags=" + Arrays.deepToString((Object[])getTags()) + ")";
}

public String getName() {
    return this.name;
}

public int getAge() {
    return this.age;
}

public double getScore() {
    return this.score;
}

public String[] getTags() {
    return this.tags;
}

public static final class Exercise<T> {
    private final String name;

    private final T value;

    public String toString() {
        return "ValueExample.Exercise(name=" + getName() + ", value=" + getValue() + ")";
    }

    private Exercise(String name, T value) {
        this.name = name;
        this.value = value;
    }

    public static <T> Exercise<T> of(String name, T value) {
        return new Exercise<>(name, value);
    }

    public boolean equals(Object o) {
        if (o == this)
            return true;
        if (!(o instanceof Exercise))
            return false;
        Exercise<?> other = (Exercise)o;
        Object this$name = getName(), other$name = other.getName();
        if ((this$name == null) ? (other$name != null) : !this$name.equals(other$name))
            return false;
        Object this$value = getValue(), other$value = other.getValue();
        return !((this$value == null) ? (other$value != null) : !this$value.equals(other$value));
    }

    public int hashCode() {
        int PRIME = 59;
        result = 1;    //不知道为什么反编译class会是这样的写法
        Object $name = getName();
        result = result * 59 + (($name == null) ? 43 : $name.hashCode());
        Object $value = getValue();
        return result * 59 + (($value == null) ? 43 : $value.hashCode());
    }

    public String getName() {
        return this.name;
    }

    public T getValue() {
        return this.value;
    }
}

}
  3.2.8、@Builder、@Singular   @Builder:通过内部类和一个全参构造器来实现构造者模式。

  @Singular:自动生成构造者模式代码,Singular是针对集合属性的特殊处理。@Singular对集合进行操作,最终会生成不可变集合

不可变集合:底层是可变集合,但是修改时会抛出异常。

  如示例:

@Builder public class SingularExample { private @Singular Set occupations; private @Singular("axis") ImmutableList axes; private @Singular SortedMap<Integer, T> elves; private @Singular Collection<?> minutiae; }   经过编译后,class文件反编译,实际的类文件等同于:

public class SingularExample { private Set occupations; private ImmutableList axes; private SortedMap<Integer, T> elves; private Collection<?> minutiae;

SingularExample(Set<String> occupations, ImmutableList<String> axes, SortedMap<Integer, T> elves, Collection<?> minutiae) {
    this.occupations = occupations;
    this.axes = axes;
    this.elves = elves;
    this.minutiae = minutiae;
}

public static <T extends Number> SingularExampleBuilder<T> builder() {
    return new SingularExampleBuilder<>();
}

public static class SingularExampleBuilder<T extends Number> {
    private ArrayList<String> occupations;
    private ImmutableList.Builder<String> axes;
    private ArrayList<Integer> elves$key;
    private ArrayList<T> elves$value;
    private ArrayList<Object> minutiae;

    public SingularExampleBuilder<T> occupation(String occupation) {
        if (this.occupations == null)
            this.occupations = new ArrayList<>();
        this.occupations.add(occupation);
        return this;
    }

    public SingularExampleBuilder<T> occupations(Collection<? extends String> occupations) {
        if (this.occupations == null)
            this.occupations = new ArrayList<>();
        this.occupations.addAll(occupations);
        return this;
    }

    public SingularExampleBuilder<T> clearOccupations() {
        if (this.occupations != null)
            this.occupations.clear();
        return this;
    }

    public SingularExampleBuilder<T> axis(String axis) {
        if (this.axes == null)
            this.axes = ImmutableList.builder();
        this.axes.add(axis);
        return this;
    }

    public SingularExampleBuilder<T> axes(Iterable<? extends String> axes) {
        if (this.axes == null)
            this.axes = ImmutableList.builder();
        this.axes.addAll(axes);
        return this;
    }

    public SingularExampleBuilder<T> clearAxes() {
        this.axes = null;
        return this;
    }

    public SingularExampleBuilder<T> elf(Integer elfKey, T elfValue) {
        if (this.elves$key == null) {
            this.elves$key = new ArrayList<>();
            this.elves$value = new ArrayList<>();
        }
        this.elves$key.add(elfKey);
        this.elves$value.add(elfValue);
        return this;
    }

    public SingularExampleBuilder<T> elves(Map<? extends Integer, ? extends T> elves) {
        if (this.elves$key == null) {
            this.elves$key = new ArrayList<>();
            this.elves$value = new ArrayList<>();
        }
        for (Map.Entry<? extends Integer, ? extends T> $lombokEntry : elves.entrySet()) {
            this.elves$key.add($lombokEntry.getKey());
            this.elves$value.add($lombokEntry.getValue());
        }
        return this;
    }

    public SingularExampleBuilder<T> clearElves() {
        if (this.elves$key != null) {
            this.elves$key.clear();
            this.elves$value.clear();
        }
        return this;
    }

    public SingularExampleBuilder<T> minutia(Object minutia) {
        if (this.minutiae == null)
            this.minutiae = new ArrayList();
        this.minutiae.add(minutia);
        return this;
    }

    public SingularExampleBuilder<T> minutiae(Collection<?> minutiae) {
        if (this.minutiae == null)
            this.minutiae = new ArrayList();
        this.minutiae.addAll(minutiae);
        return this;
    }

    public SingularExampleBuilder<T> clearMinutiae() {
        if (this.minutiae != null)
            this.minutiae.clear();
        return this;
    }

    public SingularExample<T> build() {
        Set<String> occupations;
        switch ((this.occupations == null) ? 0 : this.occupations.size()) {
            case false:
                occupations = Collections.emptySet();
                break;
            case true:
                occupations = Collections.singleton(this.occupations.get(0));
                break;
            default:
                occupations = new LinkedHashSet<>((this.occupations.size() < 1073741824) ? (1 + this.occupations.size() + (this.occupations.size() - 3) / 3) : Integer.MAX_VALUE);
                occupations.addAll(this.occupations);
                occupations = Collections.unmodifiableSet(occupations);
                break;
        }
        ImmutableList<String> axes = (this.axes == null) ? ImmutableList.of() : this.axes.build();
        SortedMap<Integer, T> elves = new TreeMap<>();
        if (this.elves$key != null)
            for (int $i = 0; $i < ((this.elves$key == null) ? 0 : this.elves$key.size()); ) {
                elves.put(this.elves$key.get($i), this.elves$value.get($i));
                $i++;
            }
        elves = Collections.unmodifiableSortedMap(elves);
        switch ((this.minutiae == null) ? 0 : this.minutiae.size()) {
            case false:
                minutiae = Collections.emptyList();
                return new SingularExample<>(occupations, axes, elves, minutiae);
            case true:
                minutiae = Collections.singletonList(this.minutiae.get(0));
                return new SingularExample<>(occupations, axes, elves, minutiae);
        }
        Collection<Object> minutiae = Collections.unmodifiableList(new ArrayList(this.minutiae));
        return new SingularExample<>(occupations, axes, elves, minutiae);
    }

    public String toString() {
        return "SingularExample.SingularExampleBuilder(occupations=" + this.occupations + ", axes=" + this.axes

           + ", elves$key=" + this.elves$key + ", elves$value=" + this.elves$value + ", minutiae=" + this.minutiae + ")"; } } }   注意:

虽然只要加上 @Builder 注解,我们就能够用流式写法快速设定对象的值,但是 setter 还是必须要写不能省略的,因为 Spring 或是其他框架有很多地方都会用到对象的 getter/setter 对他们取值/赋值,所以通常是 @Data 和 @Builder 会一起用在同个类上,既方便我们流式写代码,也方便框架做事。 由于Builder会生成一个全参构造器,导致默认的无参构造器失效,所以类采用@Builder注解后无法new出来。完美的避免方式:加上@AllArgsConstructor、@NoArgsConstructor后就可以同时使用new和构造者方式实例化对象了。 @Builder @AllArgsConstructor @NoArgsConstructor 父类中的属性子类继承问题:简单解决方案是在子类中也手动写该属性   3.2.9、@Getter(lazy=true)   可以替代经典的Double Check Lock样板代码,如下示例:

public class GetterLazyExample { @Getter(lazy = true) private final double[] cached = expensive(); private double[] expensive() { double[] result = new double[1000000]; for (int i = 0; i < result.length; i++) { result[i] = Math.asin(i); } return result; } }

//经过编译,相当于以下这个class public class GetterLazyExample { private final AtomicReference

Lombok插件使用详解及原理

标签:类对象   abstract   bre   postfix   比较   匹配   配置   script   抛出异常   

原文地址:https://www.cnblogs.com/wely9689/p/13835158.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有 京ICP备13008772号-2
迷上了代码!