04. 《Lombok 實戰 —— @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor》

JKong的二次學習日記發表於2019-01-23

《Lombok 實戰 —— @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor》

Constructors made to order: Generates constructors that take no arguments, one argument per final / non-null field, or one argument for every field.

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();
    }
}

2. @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

3. @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

4. 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;
          }
      }
      

      值得注意一點的是:@ConstructorProperties只能用在JDK 6

參考文件

.

.

.

.

.

.

相關文章