Java Lombok | コンストラクタの自動生成 - @NoArgsConstructor @RequiredArgsConstructor @AllArgsConstructor

コンストラクタを自動生成する3つのアノテーションの使い方と注意点について説明する。

コンストラクタの自動生成

コンストラクタを自動生成するアノテーションは3つある。

  • @NoArgsConstructor: 引数のないコンストラクタを自動生成する。
  • @RequiredArgsConstructor: finalとして宣言されたフィールドだけをコンストラクタ引数として自動生成する。
  • @AllArgsConstructor: すべての引数を持つコンストラクタを自動生成する。

@NoArgsConstructorの使用

@NoArgsConstructorアノテーションを宣言すると、引数のないコンストラクタを生成できる。

package com.devkuma.tutorial.lombok;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class NoArgsConstructorTutorial {

    public NoArgsConstructorTutorial(String string) {
    }

    public static void main(String[] args) {
        new NoArgsConstructorTutorial();
    }
}

@RequiredArgsConstructorの使用

@RequiredArgsConstructorアノテーションを宣言すると、finalとして宣言されたフィールドだけを引数に取るコンストラクタを自動生成できる。

package com.devkuma.tutorial.lombok;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class RequiredArgsConstructorTutorial {
    private String optional;
    private final int required;

    public static void main(String[] args) {
        new RequiredArgsConstructorTutorial(1);
    }
}

@AllArgsConstructorの使用

@AllArgsConstructorアノテーションを宣言すると、すべてのフィールドを引数に取るコンストラクタを自動生成できる。

package com.devkuma.tutorial.lombok;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class AllArgsConstructorTutorial {
    private String string;
    private int number;

    public static void main(String[] args) {
        new AllArgsConstructorTutorial("devkuma", 999);
    }
}

staticファクトリメソッドの定義

各アノテーションのstaticName属性を指定することで、staticファクトリメソッドを自動生成できる。

package com.devkuma.tutorial.lombok;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor(staticName="of")
public class StaticFactoryOfTututorial {

    private final String required;
    private int optional;

    public static void main(String[] args) {
        StaticFactoryOfTututorial tututorial = StaticFactoryOfTututorial.of("devkuma");
    }
}

使用時の注意点

@AllArgsConstructor@RequiredArgsConstructorは非常に便利にコンストラクタを生成してくれるが、何も考えずに使っていると致命的なバグが発生することがある。

問題のあるコード

次の例では@AllArgsConstructorを宣言し、xyの引数を順番に受け取るコンストラクタが自動生成されるようにしている。

package com.devkuma.tutorial.lombok.warning;

import lombok.AllArgsConstructor;
import lombok.ToString;

@AllArgsConstructor
@ToString
public class ConstructorWarning {
    private String x;
    private String y;

    public static void main(String[] args) {
        ConstructorWarning warning = new ConstructorWarning("x", "y");
        System.out.println(warning);
    }
}

実行結果:

ConstructorWarning(x=x, y=y)

問題の発生

このとき、コードを整理してxy引数の順序を次のように変更すると、2つの引数の値が入れ替わってしまう。

    private String y;
    private String x;

実行結果:

ConstructorWarning(x=y, y=x)

これはエラーも発生せず、開発者が気付かないままバグになってしまう。

解決方法

この問題は@Builderアノテーションを使用すると解決できる。

package com.devkuma.tutorial.lombok.warning;

import lombok.Builder;

@Builder
public class ConstructorSolve {
    private String x;
    private String y;

    public static void main(String[] args) {
        ConstructorSolve warning = ConstructorSolve.builder()
                                                   .x("x")
                                                   .y("y")
                                                   .build();
        System.out.println(warning);
    }
}

このように書くことで、xy引数の順序が変更されても、2つの引数の値は入れ替わらない。

参考