Help us understand the problem. What is going on with this article?

Lombok 使い方メモ

More than 1 year has passed since last update.

Lombok とは

  • 読みは、「ロンボック」もしくは「ロンボク」。
  • アノテーションを付けるだけで、 getter, setter, toString, equals などの「何度も繰り返し書くコード」をコンパイル時に自動生成してくれるようになる。
  • でも、 Getter, Setter の自動生成は無闇にやるとオブジェクト指向を破壊するので、「使ってるフレームワークがどうしても Getter, Setter を要求するから仕方ないんじゃい」ってとき以外は使うべきではないと思う。

Hello World

build.gradle
apply plugin: 'application'

configurations {
    provided
}

sourceSets {
    main { compileClasspath += configurations.provided }
}

repositories {
    mavenCentral()
}

dependencies {
    provided 'org.projectlombok:lombok:1.16.4'
}

mainClassName = 'sample.lombok.Main'
Main.java
package sample.lombok;

import lombok.Data;

@Data
public class Main {

    public static void main(String... args) {
        Main m = new Main();

        m.setString("Hello Lombok!!");
        m.setNumber(999);

        System.out.println(m);
    }

    private String string;
    private int number;
}
動作確認
$ gradle -q run
Main(string=Hello Lombok!!, number=999)
  • @Data でクラスをアノテートすることで、 getter, setter, toString などのメソッドが自動生成されている。
  • Lombok 自体はコンパイル時にのみ使用するので、依存のスコープは provided にする。

IDE で使えるようにする

Lombok のダウンロード

こちら から、 Lombok の jar ファイルをダウンロードする。

Eclipse の場合

  • ダウンロードした lombok.jar は実行可能 jar になっているので、ダブルクリックなどで起動する。
  • Lombok のインストーラが起動するので、 Specify location... をクリックする。
  • eclipse.exe が存在するフォルダを選択する。
  • Install / Update をクリックする。

Hello World を Eclipse に取り込んでみる。

build.gradle
apply plugin: 'application'
+ apply plugin: 'eclipse'

configurations {
    provided
}

sourceSets {
    main { compileClasspath += configurations.provided }
}

repositories {
    mavenCentral()
}

dependencies {
    provided 'org.projectlombok:lombok:1.16.4'
}

mainClassName = 'sample.lombok.Main'

+ eclipse {
+     project.name = 'lombok-sample'
+ 
+     classpath {
+         plusConfigurations += [configurations.provided]
+         noExportConfigurations += [configurations.provided]
+     }
+ }
Eclipseプロジェクト化
$ gradle eclipse

既存プロジェクトとして Eclipse に取り込む。

lombok.JPG

Lombok が自動生成したメソッドが認識されている。

NetBeans の場合

※バージョンは 8.0.2

Gradle プロジェクトの場合

特別な設定は必要ない。
NetBeans に Gradle プラグインを入れていれば、前述の Gradle プロジェクトを取り込むだけで有効になっている。

lombok.JPG

普通のプロジェクトの場合

  • プロジェクトの依存ライブラリに lombok.jar を追加する。
  • プロジェクトのプロパティを開き、[ビルド] > [コンパイル] の「注釈処理を有効にする」と「エディタでの注釈処理を有効にする」にチェックを入れる。

val 変数

Main.java
package sample.lombok;

import java.util.Arrays;
import java.util.HashMap;

import lombok.val;


public class Main {

    public static void main(String... args) {
        val list = Arrays.asList("hoge", "fuga", "piyo");
        list.forEach(System.out::println);

        val map = new HashMap<String, Long>();
        map.put("hoge", 1L);
    }
}
  • val という型で変数を定義すると、代入した値から良しなに型推論してくれる。

lombok.JPG

  • 総称型もちゃんと読み取ってくれる。

lombok.JPG

  • val で定義した変数は final 修飾されているので、再代入はできない。

@NonNull

Main.java
package sample.lombok;

import lombok.NonNull;

public class Main {

    public static void main(String... args) {
        method("hoge");
        method(null);
    }

    private static void method(@NonNull String value) {
        System.out.println(value);
    }
}
実行結果
hoge
Exception in thread "main" java.lang.NullPointerException: value
    at sample.lombok.Main.method(Main.java:13)
    at sample.lombok.Main.main(Main.java:10)
  • @NonNull でメソッドの引数をアノテートすると、 null チェックが自動生成される。

@Cleanup

Main.java
package sample.lombok;

import lombok.Cleanup;

public class Main {

    public static void main(String... args) {
        @Cleanup Main m = new Main();
    }

    public void close() {
        System.out.println("close メソッドが呼ばれました");
    }

    public void close(String arg) {
        System.out.println("close(String) メソッドが呼ばれました");
    }
}
実行結果
close メソッドが呼ばれました
  • @Cleanup でローカル変数をアノテートすると、スコープから抜けるときに close() メソッドが呼ばれるようになる。
実行するメソッドを指定する
package sample.lombok;

import lombok.Cleanup;

public class Main {

    public static void main(String... args) {
        @Cleanup("dispose") Main m = new Main();
    }

    public void close() {
        System.out.println("close メソッドが呼ばれました");
    }

    public void dispose() {
        System.out.println("dispose メソッドが呼ばれました");
    }
}
実行結果
dispose メソッドが呼ばれました
  • value で実行するメソッドを指定できる。

@Getter, @Setter

基本

Main.java
package sample.lombok;

import lombok.Getter;
import lombok.Setter;

public class Main {

    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;
}
実行結果
Hello @Getter, @Setter
  • @Getter でゲッターメソッドを、 @Setter でセッターメソッドを自動生成できる。

可視性を指定する

Main.java
package sample.lombok;

import lombok.AccessLevel;
import lombok.Getter;

public class Main {

    @Getter(AccessLevel.PRIVATE)
    private String value;
}

lombok.JPG

  • valueAccessLevel を渡すことで可視性を指定できる。

@Getter(lazy=true)

Main.java
package sample.lombok;

import lombok.Getter;

public class Main {

    public static void main(String[] args) {
        Main m = new Main();
        System.out.println("Main instance is created");
        m.getLazy();
    }

    @Getter
    private final String notLazy = createValue("not lazy");

    @Getter(lazy=true)
    private final String lazy = createValue("lazy");

    private String createValue(String name) {
        System.out.println("createValue(" + name + ")");
        return null;
    }
}
実行結果
createValue(not lazy)
Main instance is created
createValue(lazy)
  • @Getterlazy に true を設定すると、値の初期化をゲッターメソッドが最初に呼ばれる時まで遅延させることができる。

@ToString

Main.java
package sample.lombok;

import java.util.Arrays;
import java.util.List;

import lombok.ToString;

@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;
}
実行結果
Main(id=100, value=hoge, list=[fizz, buzz])
  • @ToString でクラスをアノテートすると、 toString() メソッドが自動生成される。
  • exclude 属性で、出力しないフィールドを指定できる。
    • クラスが相互依存してると toString() したときに無限ループが発生するので、 exclude で除外しておく必要がある。

@EqualsAndHashCode

Main.java
package sample.lombok;

import java.util.Arrays;
import java.util.List;

import lombok.EqualsAndHashCode;

@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");
}
実行結果
a.hash = 290324031
b.hash = 290324031
true
  • @EqualsAndHashCode でアノテートすると、 equals() メソッドと hashCode() メソッドが自動生成される。
  • 比較は、全てのフィールドがそれぞれ一致しているかどうかで行われる。
    • DDD だと値オブジェクトに使えるかと。

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

@NoArgsConstructor

Main.java
package sample.lombok;

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class Main {

    public Main(String string) {}
}

lombok.JPG

  • @NoArgsConstructor でアノテートすることで、引数なしのコンストラクタを定義できる。

@RequiredArgsConstructor

Main.java
package sample.lombok;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class Main {

    private String optional;
    private final int required;
}

lombok.JPG

  • @RequiredArgsConstructor でアノテートすることで、 final で修飾されたフィールドだけを引数に受け取るコンストラクタを自動生成できる。

@AllArgsConstructor

Main.java
package sample.lombok;

import lombok.AllArgsConstructor;

@AllArgsConstructor
public class Main {

    private String string;
    private int number;
}

lombok.JPG

  • @AllArgsConstructor でアノテートすることで、全てのフィールドを引数に受け取るコンストラクタを自動生成できる。

static なファクトリメソッドを定義する

Main.java
package sample.lombok;

import lombok.RequiredArgsConstructor;

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

    private final String required;
    private int optional;
}

lombok.JPG

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

@Data

Main.java
package sample.lombok;

import lombok.Data;

@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;
}
実行結果
a = Main(required=data, number=100)
true
  • @Data でクラスをアノテートすると、以下のアノテーションを全て設定したのと同じ効果を得られる。
    • @ToString
    • @Getter
    • @Setter
    • @RequiredArgsConstructor
    • @EqualsAndHashCode

@Value

Main.java
package sample.lombok;

import lombok.Value;

@Value
public class Main {

    String string;
    int number;
}

lombok.JPG

  • @Value でアノテートすることで、以下のアノテーションを設定したのと同じ効果を得られる。
    • @Getter
    • @ToString
    • @EqualsAndHashCode
    • @AllArgsConstructor
  • さらに、クラスおよび各フィールドは final になる。
  • さらに、各フィールドは自動で可視性が private になる。
  • まさに DDD の値オブジェクトか。

@Builder

Main.java
package sample.lombok;

import java.util.Arrays;
import java.util.List;

import lombok.Builder;
import lombok.ToString;

@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;
}
実行結果
Main(string=test, number=100, list=[fizz, buzz])
  • @Builder でアノテートすることで、そのクラスのビルダークラスを自動生成できる。

@Singular

デフォルトのままだと、コレクション型のフィールドも普通に上書きセッターメソッドとして自動生成される。
追加メソッドとして自動生成したい場合は @Singular でフィールドをアノテートする。

Main.java
package sample.lombok;

import java.util.Arrays;
import java.util.List;

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

@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;
}
Main.java
Main(string=test, number=100, list=[hoge, fuga, fizz, buzz])

@SneakyThrows

Main.java
package sample.lombok;

import lombok.SneakyThrows;

public class Main {

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

    @SneakyThrows
    private static void method() {
        throw new Exception("test");
    }
}
実行結果
Exception in thread "main" java.lang.Exception: test
    at sample.lombok.Main.method(Main.java:13)
    at sample.lombok.Main.main(Main.java:8)
  • @SneakyThrows でメソッドをアノテートすると、チェック例外が内部でスローされていても throws 句を書かなくて良くなる。
    • sneaky は「コソコソする」という意味。

無視できる例外を指定する

Main.java
package sample.lombok;

import java.io.IOException;

import lombok.SneakyThrows;

public class Main {

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

    @SneakyThrows(IOException.class)
    private static void method() {
        try {
            throw new Exception("test");
        } catch (Exception e) {
            // catch しないとコンパイルエラー
        }

        throw new IOException();
    }
}
  • value で例外の Class オブジェクトを渡すことで、指定した例外だけを無視できるようになる。

ロガーを使えるようにする

build.gradle
dependencies {
    provided 'org.projectlombok:lombok:1.16.4'
+   compile 'org.slf4j:slf4j-simple:1.7.12'
}
Main.java
package sample.lombok;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class Main {

    public static void main(String[] args) {
        log.info("Hello Logger!!");
    }
}
動作確認
[main] INFO sample.lombok.Main - Hello Logger!!
  • @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

参考

opengl-8080
ただのSE。Java好き。
tis
創業40年超のSIerです。
https://www.tis.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした