Lombok 实战

  • @Data : 注在类上,提供类的get、set、equals、hashCode、canEqual、toString方法
  • @AllArgsConstructor : 注在类上,提供类的全参构造
  • @NoArgsConstructor : 注在类上,提供类的无参构造
  • @Setter : 注在属性上,提供 set 方法
  • @Getter : 注在属性上,提供 get 方法
  • @EqualsAndHashCode : 注在类上,提供对应的 equals 和 hashCode 方法
  • @Log4j/@Slf4j : 注在类上,提供对应的 Logger 对象,变量名为 log ,private static final Logger log = LoggerFactory.getLogger(UserController.class);
  • @EqualsAndHashCode(callSuper = false) 作用就是自动的给model bean实现equals方法和hashcode方法,callSuper = false 表示生成的 hashcode 包括父类属性 详情参考

今天主要说下@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor

  1. @NoArgsConstructor

1.1 @NoArgsConstructor 实战使用

@NoArgsConstructor在类上使用,它可以提供一个无参构造器,比如:

@NoArgsConstructor
public class User {
    private String username;
    private String password;
}
// 编译后:
public class User {
    private String username;
    private String password;

    public User() { }
}

当然,有时候我们会使用到单例模式,这个时候我们需要将构造器私有化,那么就可以使用这样一个属性access设置构造器的权限:

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class User {
    private String username;
    private String password;
}
// 编译后:
public class User {
    private String username;
    private String password;

    private User() {
    }
}

当类中有final字段没有被初始化时,编译器会报错,但是也可用@NoArgsConstructor(force = true),那么Lombok就会为没有初始化的final字段设置默认值 0 / false / null, 这样编译器就不会报错,如下所示:

@NoArgsConstructor(force = true)
public class User {
    private final String gender;
    private String username;
    private String password;
}
// 编译后:
public class User {
    private final String gender = null;
    private String username;
    private String password;

    public User() { }
}

对于具有约束的字段(例如使用了@NonNull注解的字段),不会生成字段检查,如下所示:

@NoArgsConstructor(force = true)
public class User {
    private final String gender;
    @NonNull
    private String username;
    private String password;
}
// 编译后:
public class User {
    private final String gender = null;
    @NonNull
    private String username;
    private String password;

    public User() {
    }
}

1.2 @NoArgsConstructor 配置详解

首先来看看 @NoArgsConstructor 注解源码部分的实现:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface NoArgsConstructor {

	String staticName() default "";
    // 在构造方法的入参上添加注解。e.g. @NonNull
    // up to JDK7: @EqualsAndHashCode(onParam=@__({@AnnotationsGoHere}))
    // from JDK8: @EqualsAndHashCode(onParam_={@AnnotationsGohere})
	AnyAnnotation[] onConstructor() default {};
	// 设置构造方法的访问权限,默认是 public
	AccessLevel access() default lombok.AccessLevel.PUBLIC;
	// 是否强制对未赋值的final字段初始化值。
	boolean force() default false;

	@Deprecated
	@Retention(RetentionPolicy.SOURCE)
	@Target({})
	@interface AnyAnnotation {}
}

看到有这样一个注解属性:staticName,是代表什么意思呢?
也就是说是否生成静态的构造方法,如果生成静态的构造方法,那么原来的实例构造方法将会被私有(private),然后创建一个你指定名称的静态构造方法,并且是public的,如下所示:

@NoArgsConstructor(staticName = "UserHa")
public class User {
    private String username;
    private String password;
}
// 编译后:
public class User {
    private String username;
    private String password;

    private User() { }

    public static User UserHa() {
        return new User();
    }
}
  1. @RequiredArgsConstructor

2.1 @RequiredArgsConstructor 实战使用

@RequiredArgsConstructor也是在类上使用,但是这个注解可以生成带参或者不带参的构造方法。

若带参数,只能是类中所有带有 @NonNull注解的和以final修饰的未经初始化的字段,如下所示:

@RequiredArgsConstructor
public class User {
    private final String gender;
    @NonNull
    private String username;
    private String password;
}

// 编译后:
public class User {
    private final String gender;
    @NonNull
    private String username;
    private String password;

    public User(String gender, @NonNull String username) {
        if (username == null) {
            throw new NullPointerException("username is marked @NonNull but is null");
        } else {
            this.gender = gender;
            this.username = username;
        }
    }
}

如果针对User类使用@RequiredArgsConstructor注解实现空参构造方法,那么我们就要这样定义实体类:

@RequiredArgsConstructor
public class User {
    private final String gender = "男";
    private String username;
    private String password;
}

当然如果我们要是想生成空参构造,仅适用上一个注解@NoArgsConstructor就可以了。

2.2 @RequiredArgsConstructor 配置详解

先撸注解源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface RequiredArgsConstructor {
	// 是否使用静态构造器,并制定静态构造器的名称
	String staticName() default "";
	// 构造器入参添加注解
	AnyAnnotation[] onConstructor() default {};

	@Deprecated
	@Retention(RetentionPolicy.SOURCE)
	@Target({})
	@interface AnyAnnotation {}
}

没什么好说的,可以参见@NoArgsConstructor

  1. @AllArgsConstructor

3.1 @AllArgsConstructor 实战使用

@AllArgsConstructor同样是在类上使用,该注解提供一个全参数的构造方法,默认不提供无参构造。

需要注意的是,这里的全参不包括已初始化的final字段(主要是final字段,一旦被赋值不允许再被修改)。

@AllArgsConstructor
public class User {
    private final String gender;
    private String username;
    private String password;
}
// 编译后
public class User {
    private final String gender;
    private String username;
    private String password;

    public User(String gender, String username, String password) {
        this.gender = gender;
        this.username = username;
        this.password = password;
    }
}

3.2 @AllArgsConstructor 配置详解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface AllArgsConstructor {
	// 是否使用静态构造器,并制定静态构造器的名称
	String staticName() default "";
	// 构造器入参添加注解
	AnyAnnotation[] onConstructor() default {};
	// 设置构造器的访问权限
	AccessLevel access() default lombok.AccessLevel.PUBLIC;

	@Deprecated
	@Retention(RetentionPolicy.SOURCE)
	@Target({})
	@interface AnyAnnotation {}
}

同样这几个属性配置方式,也可以参见@NoArgsConstructor

  1. Constructor 全局配置
    # 如果设置为true,则lombok将向生成的构造函数添加 @java.beans.ConstructorProperties。
    lombok.anyConstructor.addConstructorProperties = [true | false] (default: false)
    # 是否禁用这几种构造器注解
    lombok.[allArgsConstructor|requiredArgsConstructor|noArgsConstructor].flagUsage = [warning | error] (default: not set)
    lombok.anyConstructor.flagUsage = [warning | error] (default: not set)
    # 是否支持复制现有的注解,在本类中使用。e.g. @Nullable/@NonNull annotations
    lombok.copyableAnnotations = [A list of fully qualified types] (default: empty list)
    

测试 addConstructorProperties

全局配置文件内容

config.stopBubbling = true
# 首先清除原有配置
clear lombok.anyConstructor.addConstructorProperties
# 设置新的配置
lombok.anyConstructor.addConstructorProperties = true

实体类

@AllArgsConstructor
public class User {
    private String username;
    private String password;
}
// 编译后:
public class User {
    private String username;
    private String password;

    @ConstructorProperties({"username", "password"})		// 被添加
    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
}