Lombok とは
Lombok は、 Java言語におけるボイラープレートコードをソースコードから排除するために使用するライブラリです。 ボイラープレートコードとは、何度も繰り返し書く言語仕様上省く事ができない定型的なコードの事で、本質的なロジックでないためアプリケーションを実装する上で冗長なコードとなってしまいます。
Java言語における代表的なボイラープレートコード
- メンバー変数にアクセスするための getter / setter メソッド
equals
/hashCode
メソッドtoString
メソッド- コンストラクタ
- リソース(入出力ストリーム等)のクローズ処理
- ロガーインスタンスの生成
Lombokは、これらのボイラープレートコードをコンパイル時に生成することで、 開発者が実装するソースコード上から冗長なコードを取り除く仕組みを提供しています。
Lombokを使用して作成したJavaBeanのソースコード
import lombok.Data;
@Data
public class SampleForm {
String id;
String name;
}
クラスレベルに@lombok.Data
アノテーションを付与するだけで、 JavaBeanとして必要なメソッドがLombokによって生成されます。
これは、Lombokの@Data
アノテーションを付与しただけで、約10行のソースコードから、 約60行ある下記のソースコード(Eclipseの自動生成機能を使用して出力したソースコード)によって生成されるクラスと同じ効果を得る事ができる事を意味しています。
public class Sample {
private Integer id;
private String name;
public Sample() {
}
public Integer getId() {
return id;
}
public void setId(Integer _id) {
this.id = _id;
}
public String getName() {
return name;
}
public void setName(String _name) {
this.name = _name;
}
@Override
public int hashCode() {
final int id = 31;
int result = 1;
result = id * result
+ ((name == null) ? 0 : name.hashCode());
result = id * result + ((name == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Sample other = (Sample) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
IDEと Lombok を連携する
LombokをIDE上で使用する場合は、IDEが提供するコンパイル(ビルド)機能と連携するために、 LombokをIDEにインストールする必要があります。
Lombokのインストール
Lombokのjarファイルは、以下のどちらかから取得します。
- Lombokのダウンロードページ
- Mavenのローカルリポジトリ(通常は、
$HOME/.m2/repository/org/projectlombok/lombok/<version>/lombok-<version>.jar
)
Eclipse の場合
- ダウンロードした
lombok.jar
は実行可能 jar になっているので、ダブルクリックなどで起動する。 - Lombok のインストーラが起動するので、
Specify location...
をクリックする。 eclipse.exe
が存在するフォルダを選択する。Install / Update
をクリックする。
代表的なLombokの機能
val 変数
val
という型で変数を定義することで、代入した値から良しなに型推論してくれるようになります。総称型も読み取る事が可能です。val
で定義した変数は final
修飾されているので、再代入はできません。
val map = new HashMap<String, Long>();
map.put("hoge", 1L);
@NonNull
@NonNull
でメソッドの引数をアノテートすると、 null チェックが自動生成されます。
private static void method(@NonNull String value) {
System.out.println(value);
}
@Cleanup
@Cleanup
でローカル変数をアノテートすると、スコープから抜けるときに close()
メソッドが呼ばれるようになります。
public static void main(String... args) {
@Cleanup Main m = new Main();
}
public void close() {
System.out.println("close メソッドが呼ばれました");
}
@Cleanup
の引数を指定すると 実行するメソッドを指定することも出来ます。
public static void main(String... args) {
@Cleanup("dispose") Main m = new Main();
}
public void dispose() {
System.out.println("dispose メソッドが呼ばれました");
}
@Getter, @Setter
@Getter
でゲッターメソッドを、 @Setter
でセッターメソッドが自動生成されます。
public static void main(String... args) {
Main m = new Main();
m.setValue("Hello @Getter, @Setter");
System.out.println(m.getValue());
}
@Getter @Setter
private String value;
value に AccessLevel を渡すことで可視性を指定する
@Getter(AccessLevel.PRIVATE)
private String value;
値の初期化をゲッターメソッドが最初に呼ばれる時まで遅延させる
@Getter(lazy=true)
private final String lazy = createValue("lazy");
@ToString
@ToString
でクラスをアノテートすると、 toString()
メソッドが自動生成されます。 また、exclude
属性で、出力しないフィールドを指定する事ができます。
@ToString(exclude="ignore")
public class Main {
public static void main(String[] args) {
System.out.println(new Main());
}
private int id = 100;
private String value = "hoge";
private List<String> list = Arrays.asList("fizz", "buzz");
private double ignore = 999;
}
@EqualsAndHashCode
@EqualsAndHashCode
でアノテートすると、 equals()
メソッドと hashCode()
メソッドが自動生成されます。 比較は、全てのフィールドがそれぞれ一致しているかどうかで行われます。
@EqualsAndHashCode
public class Main {
public static void main(String[] args) {
Main a = new Main();
Main b = new Main();
System.out.println("a.hash = " + a.hashCode());
System.out.println("b.hash = " + b.hashCode());
System.out.println(a.equals(b));
}
private int id = 100;
private String value = "hoge";
private List<String> list = Arrays.asList("fizz", "buzz");
}
コンストラクタの自動生成
@NoArgsConstructor
@NoArgsConstructor
でアノテートすることで、引数なしのコンストラクタを定義できます。
@NoArgsConstructor
public class Main {
public Main(String string) {}
}
@RequiredArgsConstructor
@RequiredArgsConstructor
でアノテートすることで、 final
で修飾されたフィールドだけを引数に受け取るコンストラクタを自動生成できます。
@RequiredArgsConstructor
public class Main {
private String optional;
private final int required;
}
@AllArgsConstructor
@AllArgsConstructor
でアノテートすることで、全てのフィールドを引数に受け取るコンストラクタを自動生成できます。
@AllArgsConstructor
public class Main {
private String string;
private int number;
}
static なファクトリメソッドを定義する
各アノテーションで staticName
属性を指定することで、 static なファクトリメソッドを自動生成できます。
@RequiredArgsConstructor(staticName="of")
public class Main {
private final String required;
private int optional;
}
@Data
@Data
でクラスをアノテートすると、以下のアノテーションを全て設定したのと同じ効果を得られる。
@ToString
@Getter
@Setter
@RequiredArgsConstructor
@EqualsAndHashCode
@Data
public class Main {
public static void main(String[] args) {
Main a = new Main("data");
a.setNumber(100);
Main b = new Main("data");
b.setNumber(100);
System.out.println("a = " + a);
System.out.println(a.equals(b));
}
private final String required;
private int number;
}
@Value
@Value
でアノテートすることで、以下のアノテーションを設定したのと同じ効果を得られます。また、クラスおよび各フィールドは final
となり、 各フィールドは自動で可視性が private
になります。
@Getter
@ToString
@EqualsAndHashCode
@AllArgsConstructor
@Value
public class Main {
String string;
int number;
}
@Builder
@Builder
でアノテートすることで、そのクラスのビルダークラスを自動生成できます。
@Builder
@ToString
public class Main {
public static void main(String[] args) {
MainBuilder builder = Main.builder()
.string("test")
.number(100)
.list(Arrays.asList("hoge", "fuga"))
.list(Arrays.asList("fizz", "buzz"));
Main m = builder.build();
System.out.println(m);
}
private String string;
private int number;
private List<String> list;
}
@Singular
デフォルトのままだと、コレクション型のフィールドも普通に上書きセッターメソッドとして自動生成されます。追加メソッドとして自動生成したい場合は @Singular でフィールドをアノテートします。
@Builder
@ToString
public class Main {
public static void main(String[] args) {
MainBuilder builder = Main.builder()
.string("test")
.number(100)
.list("hoge")
.list("fuga")
.list(Arrays.asList("fizz", "buzz"));
Main m = builder.build();
System.out.println(m);
}
private String string;
private int number;
@Singular("list")
private List<String> list;
}
@SneakyThrows
@SneakyThrows
でメソッドをアノテートすると、チェック例外が内部でスローされていても throws
句を書かなくて良くなります。
@SneakyThrows
private static void method() {
throw new Exception("test");
}
無視できる例外を指定する
value
で例外の Class
オブジェクトを渡すことで、指定した例外だけを無視できるようになります。
@SneakyThrows(IOException.class)
private static void method() {
try {
throw new Exception("test");
} catch (Exception e) {
// catch しないとコンパイルエラー
}
throw new IOException();
}
ロガーを使えるようにする
@Slf4j
でクラスをアノテートすることで、 log
という名前の static final なロガーが使えるようなります。 Slf4j 以外にも、以下のロガーに対応している。
アノテーション | ロガークラス |
@CommonsLog | org.apache.commons.logging.Log |
@Log | org.apache.commons.logging.Log |
@Log4j | org.apache.log4j.Logger |
@Log4j2 | org.apache.logging.log4j.Logger |
@Slf4j | org.slf4j.Logger |
@XSlf4j | org.slf4j.ext.XLogger |
@Slf4j
public class Main {
public static void main(String[] args) {
log.info("Hello Logger!!");
}
}