# lombok

# 原理

# @Data

该注解同时包含以下注解:相当于一个注解集合
@Getter
@Setter
@RequiredArgsConstructor
@ToString
@EqualsAndHashCode

# 默认不调用父类的@EqualsAndHashCode

如果@Data注解的类存在父类,默认在equals方法中不会调用父类的equals。(HashCode同理)

通常IDEA会给出警告提示:
Generating equals/hashCode implementation but without a call to superclass, even though this class does not extend java.lang.Object. If this is intentional, add '(callSuper=false)' to your type. 此时给类加上@EqualsAndHashCode(callSuper = true)注解即可解决,因为通常类的比较需要用所有属性。

# 使用@Data同时再使用其包含的注解子集,会覆盖其相应功能

如果再使用@ToString(callSuper = true)注解,则会覆盖@Data的@ToString

# @ToString

// 生成的toString方法中是否包含字段名称
boolean includeFieldNames() default true;

// 排除哪些字段
String[] exclude() default {};

// 指定只打印哪些字段
String[] of() default {};

// 是否调用父类的toString方法,作为当前类toString的一部分。
boolean callSuper() default false;

// 默认调用field的getter方法
boolean doNotUseGetters() default false;

// 只包含显式指定@ToString.Include的字段
boolean onlyExplicitlyIncluded() default false;

// 不包含此注解的字段
public @interface Exclude {}

// 可用于方法或者field
// method:包含方法的返回值
// field:包含此字段
public @interface Include {
// 指定打印优先级,值越大越优先
int rank() default 0;

// 要在生成的{@code toString()}中显示的名称,此外,如果此批注位于方法上,并且名称与现有字段匹配,则会替换该字段。
String name() default "";
}

# 如何使用@builder

# 引入lombok依赖

# 在类上标记@builder

# 最好类同时加上@AllArgsConstructor(access = AccessLevel.PRIVATE)

只加@builder, 生成的代码, 包含的构造器是default的, 也就是没有任何修饰的, 能被同包中类创建, 因此加上此注解后, 便无法直接创建此类实例, 必须通过构建器模式创建.

# 如何使用

直接使用类名.builder()创建一个构造器类, 然后通过构造器类设置属性, 最后build()生成本类.

//示例
Person.PersonBuilder builder = Person.builder().id(15).name("jesse");
//每一次调用build()都会生成一个新的不可变的实例
Person p = builder.build();
//builder构建实例, 可以重复调用

# 何时该使用构建器模式

创建类实例, 一般有3种做法:

  1. 使用构造函数
  2. 使用java bean方式(set方式)
  3. 构建器模式

创建类实例时, 其属性很多, 并且属性的组合也很多(说明参数基本都是可选的), 如果使用构造函数的话, 会重载很多次构造函数, 而java bean的方式不方便进行链式调用, 此时使用构建器模式就相当合适了.

# 实现原理

其实就是帮你实现了builder(构建器)设计模式, 反编译后的代码在下面, 一看就懂了, 不懂就得去了解一下设计模式了.

# 反编译前

@builder
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Person {
    private Integer id;
    private String name;
}

# 反编译后

public class Person {
    private Integer id;
    private String name;

    private Person(final Integer id, final String name) {
        this.id = id;
        this.name = name;
    }

    public static Person.PersonBuilder builder() {
        return new Person.PersonBuilder();
    }

    public static class PersonBuilder {
        private Integer id;
        private String name;

        PersonBuilder() {
        }

        public Person.PersonBuilder id(final Integer id) {
            this.id = id;
            return this;
        }

        public Person.PersonBuilder name(final String name) {
            this.name = name;
            return this;
        }

        public Person build() {
            return new Person(this.id, this.name);
        }

        public String toString() {
            return "Person.PersonBuilder(id=" + this.id + ", name=" + this.name + ")";
        }
    }
}

# @data

这里是准备说一些关于lombok的注意事项, 因为它有些坑是不太明显的, 但有时会造成比较大的问题, 排查lombok相关问题, 主要通过查看编译后的文件来解决.

在使用@data时, lombok会帮你生成equals()和hashcode()方法, 这是很多人都不清楚的,equals()中它会帮你针对每一个field去比较, 但是请注意, 它不会帮你比较父类中的field, 因此在使用时可能会出现莫名其妙的问题.

# 场景重现

为了说明上面描述的这个问题, 下面以Person和Son两个类来说明

父类

@Data
public class Person {
    private String name;
    private int age;
}

子类

@Data
public class Son extends Person {
    private String toy;
}

测试类

测试方法中s1和s2两者的toy值相等

# @SneakyThrows

https://www.jianshu.com/p/f33e3ca7f102

修改于: 8/11/2022, 3:17:56 PM