覚えたら書く

IT関係のデベロッパとして日々覚えたことを書き残したいです。twitter: @yyoshikaw

Lombok - @Builderでデフォルト値を指定する

Lombok@Builderアノテーションは何かと便利なのですが、プロパティへ値をセットするためのBuilderのメソッドを呼ばないと対応するフィールドが初期値(数値なら0, booleanならfalse, オブジェクトならnull)になってしまいます。

このあたりの動きをv1.16.16で増えた@Builder.Defaultで改善できるようになっています。


Builderで値をセットしなかった時の動きの確認

動作確認用にPerson1というクラスを用意して@Builderを付与します。
Person1をBuilderを通じて2回生成します。1回目は全プロパティをセットしますが2回目はnameプロパティに値をセットしません。

import lombok.Builder;
import lombok.Value;

@Builder
@Value
public class Person1 {

    private final long id;

    private final String name;

    private final String description;
}


■呼び出し側のコード

public final class Person1Client {

    public static void main(String[] args) {
        Person1 p1a = Person1.builder()
                .id(10L)
                .name("Taro")
                .description("name set person.")
                .build();

        System.out.println("p1a#toString: " + p1a);

        // nameメソッドを呼ばない
        Person1 p1b = Person1.builder()
                .id(20L)
                .description("name not set person.")
                .build();

        System.out.println("p1b#toString: " + p1b);
    }
}


■実行結果

結果としてPerson1生成の2回目の呼び出しではnameの値がnullになっています。

p1a#toString: Person1(id=10, name=Taro, description=name set person.)
p1b#toString: Person1(id=20, name=null, description=name not set person.)

対象オブジェクトの生成側が全プロパティをセットするのが必須ならいいですが、そうでないケースもあると思います。
そういう場合にはセットしなかったプロパティにはデフォルト値を入れておきたいところです。


デフォルト値をセットしたい時は

デフォルト値を入れておきたいという要望に応えるための方法として若干裏技的に以下リンク先のような方法が存在しています。

@Builderアノテーションによって生み出されるコードを逆手に取ったような手法になっています。


@Builder.Default によるデフォルト値セット

Lombokのv1.16.16から@Builderでのデフォルト値指定のための@Builder.Defaultが追加されました

デフォルト値をセットしたいフィールドに@Builder.Defaultアノテーションを付与して、フィールドにデフォルト値をセットします。

本サンプルではnameフィールドに "<UNKNOWN>"という値をデフォルト値としてセットします

import lombok.Builder;
import lombok.Value;

@Builder
@Value
public class Person2 {

    private final long id;

    @Builder.Default
    private final String name = "<UNKNOWN>";

    private final String description;
}


■呼び出し側のコード

public final class Person2Client {

    public static void main(String[] args) {
        Person2 p2a = Person2.builder()
                .id(10L)
                .name("Taro")
                .description("name set person.")
                .build();

        System.out.println("p1a#toString: " + p2a);


        // nameメソッドを呼ばない
        Person2 p2b = Person2.builder()
                .id(20L)
                .description("name not set person.")
                .build();

        System.out.println("p2b#toString: " + p2b);
    }
}


■実行結果

結果を見ると、Builderのnameメソッドを呼ばない場合はデフォルト値(<UNKNOWN>)がセットされていることが分かります

p1a#toString: Person2(id=10, name=Taro, description=name set person.)
p2b#toString: Person2(id=20, name=<UNKNOWN>, description=name not set person.)


補足

実は私がこのエントリ書いてる段階では、IntelliJのIDE上では、@Builder.Defaultを付与したフィールドへBuilderで値をセットするメソッドがコンパイルエラーになってしまいました。
ただし、ビルドや実行はできるので、Lombokのpluginが対応できていないだけなのかもしれません。

EclipseであればIDE上も何もエラー出ませんでした。



関連エントリ