Lombok でできること確認します。( @Singular )

2021年5月6日

前回 Lombok の @Builder を用いた引数の長いメソッドの解消法について確認しました。
今回はもう少し頭が良い(?) @Singular を確認したいと思います。

Collectionを渡したいわけでは・・・

先日確認した @Builder はすごいパワフルな機能でした。
しかしこの @Builderはコレクションの扱いが今一歩といったところがあるようです。

package com.example.demo;

import java.util.List;

import lombok.Builder;
import lombok.ToString;

@ToString
@Builder
public class HogeLombok {
	private int age;
	private String name;
	private String tokugi;
	private String hobby;
	@Builder.Default private String school = "デフォルト高校";	// デフォルト値を変更することも可能
	private int opt01;
	private int opt02;
	private List groups;	// ← New!
	
	/**
	 * ClassName+Builder でデフォルト値の指定が可能です。
	 */
	public static class HogeLombokBuilder {
		private int opt02 = -100;
	}
}

HogeLombokクラスに groups メンバを追加しました。
このメンバには所属しているグループをいくつでも登録できるようにしておきます。

使うほうのクラスを実装しましょう。グループは「生き物係」と「野球部」を登録するものとします。

package com.example.demo;

import java.util.ArrayList;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
		
		// インスタンス化!
		HogeLombok v = HogeLombok.builder()
				.age(100)
				.name("太郎")
				.tokugi("柔道")
				.groups(new ArrayList() {{this.add("生き物係");this.add("野球部");}}) // !!
				.build();
				
		System.out.println("v " + v);
	}
}

あえて妙なコードを実装しておきました。
ArrayListオブジェクトを生成し、さらに「生き物係」「野球部」を登録しgroupsに渡しています。

しかしあまりスマートには見えませんよね。
実現したいことは「生き物係」と「野球部」の登録だけですからね。
実際のお仕事でもこういった状況はよくあります。

一度目的のコレクションをインスタンス化して、値を格納。
その後メソッドの引数に渡す・・・。慣れてしまえば億劫でもないのですがなんだかまどろっこしいですよね。

 

Lombok のコレクションを自動生成する機能

Lombok ではこの問題を解決するために @Singular というアノテーションを持っています。
このアノテーションは @Builder を強化するような形で使用するのが一般的なようです。
機能としてはコレクションクラスを自動生成し、呼び出し側のbuilderメソッドでは「コレクションに1件追加する」という振る舞いに変更する機能ようです。

確認してみよう

ということで使ってみました。

package com.example.demo;

import java.util.List;

import lombok.Builder;
import lombok.Singular;
import lombok.ToString;

@ToString
@Builder
public class HogeLombok {
	private int age;
	private String name;
	private String tokugi;
	private String hobby;
	@Builder.Default private String school = "デフォルト高校";	// デフォルト値を変更することも可能
	private int opt01;
	private int opt02;
	@Singular
	private List groups;	// ← New!
//	@Singular
//	private String[] phones;	// 配列には使えない。
	
	/**
	 * ClassName+Builder でデフォルト値の指定が可能です。
	 */
	public static class HogeLombokBuilder {
		private int opt02 = -100;
	}
}

上記実装にもコメントで書きましたが、配列メンバには使えないようです。
お仕事では配列を用いることも多いので惜しいなぁ・・・なんて思ってしまいました。

この @Singular を付与する際、1つ注意したいのがメンバ名です。
基本はメンバ名に「三単現のs」を付与します。
これを守って実装した場合はbuilderメソッドを使用する側では三単現のsが付かないメソッドを用いて要素の追加ができます。
これ以外のメンバ名を使用する場合は @Singular アノテーションの引数に1要素を表す文字列を渡します。
別の視点から考えると、呼び出し側でのメソッド名を @Singular アノテーションの引数を用いて決定することができるということです。

 

呼び出し側の実装です。

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(DemoApplication.class, args);
		
		// インスタンス化!
		HogeLombok v = HogeLombok.builder()
				.age(100)
				.name("太郎")
				.tokugi("柔道")
				.group("生き物係")
				.group("野球部")
				.build();
				
		System.out.println("v " + v);
	}
}

 

コードがすっきりしましたね!

実行してみよう

実行してみました。

 

ばっちりgroupsが登録されましたね。

 

まとめ

Lombok の @Singular について確認しました。
配列に使えないのは残念!と思ってしまいましたがそれを十分に補うほどこの機能のすごさを実感しました。
冗長なコードを記載することを回避するということは欠陥を作りこみにくいということですからね。

今日はここまで!