Lombokの使い方

Lombok(ロンボク・ロンボック)とはJava向けのライブラリで、アノテーションをつけるだけで冗長なコード(いわゆるボイラープレートコード)を自動生成してくれるとても便利なツールです。
Lombokを使うことでコードの記述量が大幅に削減できるため、生産性の向上にもつながります。

公式サイト https://projectlombok.org/

導入

Gradle

build.gradleにライブラリを追加します。

dependencies {
    compileOnly 'org.projectlombok:lombok:1.18.20'
    annotationProcessor 'org.projectlombok:lombok:1.18.20'
}

Maven

pom.xmlにライブラリを追加します。

<dependencies>
  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.20</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

IDEの設定

Eclipse (Windows)

  1. 公式サイトからjarファイルをダウンロード
    https://projectlombok.org/download
  2. ダウンロードしたjarファイルをダブルクリック
  3. インストーラーが開くのでインストール先のEclipseにチェックを入れ、「Install / Update」ボタンをクリック

以上でインストール完了です。

IntelliJ IDEA

組み込みのプラグインが内蔵されているため、特にインストールは必要ありません。

アノテーション一覧

val

val型を使い変数を定義すると代入された値から型推論をしてくれます。
valはfinal型となるため、再代入はできません。

import lombok.val;

import java.time.LocalDateTime;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        // val 文字列型を代入しているのでvalはString型に推論される
        val name = "TARO";
        
        // final型なので再代入は不可
        // name = "JIRO";
        
        // 総称型もちゃんと認識されます
        val map = new HashMap<String, Integer>();
        map.put("HOGE", 10);
    }
}

ただし、Java10から導入されたvarにfinal修飾することで同様の機能が実現できるのであまり出番がないのではないかと思います。

@NonNull

@NonNullはメソッドやコンストラクタのパラメータに付与する事で自動的にNULLチェックを行ってくれます。

import lombok.NonNull;

public class NonNullSample {
    public void execute(@NonNull String name) {
        System.out.println(name.toUpperCase());
    }
}

上のサンプルの場合、nameパラメータがnullの場合にNullPointerExceptionがスローされます。
コンストラクタの引数の場合はthisやsuperが明示的に実行され、その後にnullチェックが行われます。

ちなみにlombokにはデフォルトの挙動を設定するための機能があり、プロジェクトのフォルダ直下にlombok.configというファイルを配置する事で使用することができます。
例えば@NonNullアノテーションでは標準でNullPointerExceptionがスローされますが、この挙動をカスタマイズすることができます。

lombok.nonNull.exceptionType = JDK

上記の設定ではjava.util.Objects.requireNonNullを使ったnullチェックを行うように設定しています。

@Cleanup

ローカル変数に対して@Cleanupを付与する事でその変数が属するスコープを抜ける際に自動的にcloseメソッドを実行します。

import lombok.Cleanup;

public class CleanupSample {
    public void execute() {
        @Cleanup var hoge = new Hoge();
        hoge.execute();
    }

    // ↓のコードが生成されます
    /*
    public void execute() {
        Hoge hoge = new Hoge();
        try {
            hoge.execute();
        } finally {
            if (hoge != null) {
                hoge.close();
            }
        }
    }
    */

    public static class Hoge {
        public void execute() {
            System.out.println("HOGE");
        }

        public void close() {
            System.out.println("Close HOGE");
        }
    }
}

また、@Cleanupのvalue属性に実行するメソッド名を指定することも可能です。

import lombok.Cleanup;

public class CleanupSample {
    public void execute() {
        @Cleanup("after") var fuga = new Fuga();
        fuga.execute();
    }

    public static class Fuga {
        public void execute() {
            System.out.println("FUGA");
        }

        public void after() {
            System.out.println("Close FUGA");
        }
    }
}

InputStreamやOutputStreamに代表されるCloseableインターフェースの実装クラスを扱う際に非常に重宝しますね。

@Getter @Setter

@Getter, @Setterアノテーションはクラスフィールドに付与することで、getter, setterを自動生成します。

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

public class User {
    @Getter
    @Setter
    private String name;

    // ↓ 自動生成されるコード
    /*
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }
    */
    
    // AccessLevelを指定することで可視性を指定可能
    @Setter(AccessLevel.PROTECTED)
    private int age;

    // ↓ 自動生成されるコード
    /*
    protected void setAge(int age) {
        this.age = age;
    }
    */

    @Getter
    private boolean invalid;

    // ↓ 自動生成されるコード (booleanの場合はisXXとなる)
    /*
    public boolean isInvalid() {
        return this.invalid;
    }
    */
}

またクラスに指定した場合はそのクラスの全ての非staticフィールドに対してgetter及びsetterを自動生成します。

import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;

@Getter @Setter
public class Item {
    private String itemId;
    private String itemName;
    
    // getter, setterを生成したくない場合は個別にAccessLevel.NONEを指定
    @Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE)
    private boolean hidden;
}

@Getterにlazy=trueを指定することで、フィールドへの初期値の代入をgetterの初回呼び出しまで遅延させることができます。フィールドの初期化処理のコストが高い場合に有効です。lazyはfinalフィールドにのみ設定可能です。

    @Getter(lazy = true)
    private final String text = createInitialText();

    private String createInitialText() {
        var sb = new StringBuilder();
        for (int i = 0; i < 1000; i++) {
            sb.append("*");
        }
        return sb.toString();
    }

@ToString

@ToStringはクラスに付与することで、toStringメソッドを自動生成することができます。

import lombok.ToString;

@ToString
public class ToStringSample {
    private String name;
    private int age;

    // ↓ 自動生成されるコード
    /*
    public String toString() {
        return "ToStringSample(name=" + this.name + ", age=" + this.age + ")";
    }
    */
}

@ToStringはサンプルのようにデフォルトでクラス名とカンマ区切りで連結したフィールド名と値が生成されますが、includeFieldNamesパラメータをfalseにセットすることで、フィールド名が出力されなくなります。

import lombok.ToString;

@ToString(includeFieldNames = false)
public class ToStringSample {
    private String name;
    private int age;

    // ↓ 自動生成されるコード
    /*
    public String toString() {
        return "ToStringSample(" + this.name + ", " + this.age + ")";
    }
    */
}

注意したいのはクラスのフィールドに自分自身を保持するようなクラスがあった場合は、無限ループになってしまいます。その場合は対象のフィールドをtoStringから除外する必要があります。

@ToString(exclude = "employees") // (1) 除外するフィールドを指定(複数指定可)
public class Company {
    private int id;
    private String companyName;
    private List<Employee> employees;
}

@ToString
public class Employee {
    private String employeeNo;
    private String name;
    @ToString.Exclude // (2) 除外するフィールドにToString.Excludeアノテーションを付与
    private Company company;
}

フィールドを除外するには@ToStringアノテーションにexclude属性を指定する方法(1)と除外するフィールドに@ToString.Excludeアノテーションを付与する方法(2)の2種類の設定方法があります。

また除外とは逆にtoStringに含めるフィールドを指定することも可能です。

@ToString(of = {"id", "companyName"}) // (1) toStringに含めるフィールドを指定(複数指定可)
public class Company {
    private int id;
    private String companyName;
    private List<Employee> employees;
}

@ToString(onlyExplicitlyIncluded = true) // (2) ToString.Includeが付与されたフィールドのみ含めるように設定
public class Employee {
    @ToString.Include // (2) 対象に含めるフィールドにToString.Includeアノテーションを付与
    private String employeeNo;
    @ToString.Include
    private String name;
    private Company company;
}

こちらも@ToStringアノテーションにof属性を指定する方法(1)と対象に含めるフィールドに@ToString.Includeアノテーションを付与する方法(2)の2種類の設定方法があります。

@ToStringアノテーションにcallSuper属性をtrueに指定することで、スーパークラスのtoStringの結果を含めることができます。

@EqualsAndHashCode

@EqualsAndHashCodeはequalsメソッドとhashCodeメソッドを自動生成することができます。

import lombok.EqualsAndHashCode;

@EqualsAndHashCode
public class EqualsAndHashCodeSample {
    private String name;
    private int age;

    // ↓ 自動生成されるコード
    /*
    public boolean equals(final Object o) {
        if (o == this) return true;
        if (!(o instanceof EqualsAndHashCodeSample)) return false;
        final EqualsAndHashCodeSample other = (EqualsAndHashCodeSample) o;
        if (!other.canEqual((Object) this)) return false;
        final Object this$name = this.name;
        final Object other$name = other.name;
        if (this$name == null ? other$name != null : !this$name.equals(other$name)) return false;
        if (this.age != other.age) return false;
        return true;
    }

    protected boolean canEqual(final Object other) {
        return other instanceof EqualsAndHashCodeSample;
    }

    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        final Object $name = this.name;
        result = result * PRIME + ($name == null ? 43 : $name.hashCode());
        result = result * PRIME + this.age;
        return result;
    }
    */
}

@EqualsAndHashCodeでは@ToStringと同様にexclude, of, callSuper, onlyExplicitlyIncludedなどの属性が利用可能です。

@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor

@NoArgsConstructor:引数なしコンストラクタ

@NoArgsConstructorは引数なしのコンストラクタを自動生成します。

import lombok.NoArgsConstructor;

@NoArgsConstructor
public class ConstructorSample {
    // ↓ 自動生成されるコード
    /*
    public ConstructorSample() {
    }
    */
}

AccessLevel属性を指定することでコンストラクタの可視性を指定することが可能です。

import lombok.NoArgsConstructor;
import lombok.NoArgsConstructor;

@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ConstructorSample {
    // ↓ 自動生成されるコード
    /*
    protected ConstructorSample() {
    }
    */
}

staticName属性を指定することでインスタンス生成用のstaticメソッドを生成することができます。

import lombok.NoArgsConstructor;

@NoArgsConstructor(staticName = "newInstance")
public class ConstructorSample {
import lombok.NoArgsConstructor;

@NoArgsConstructor(staticName = "newInstance")
public class ConstructorSample {
    // ↓ 自動生成されるコード
    /*
    private ConstructorSample() {
    }

    // インスタンス生成用staticメソッド
    public static ConstructorSample newInstance() {
        return new ConstructorSample();
    }
    */
}
@RequiredArgsConstructor:必須フィールドコンストラクタ

@RequiredArgsConstructorはfinal指定されたフィールドを引数に持つコンストラクタを自動生成します。

import lombok.RequiredArgsConstructor;

import java.time.LocalDate;

@RequiredArgsConstructor
public class ConstructorSample {
    private final String name;
    private int age;
    private final LocalDate birthday;

    // ↓ 自動生成されるコード
    /*
    public ConstructorSample(String name, LocalDate birthday) {
        this.name = name;
        this.birthday = birthday;
    }
    */
}
@AllArgsConstructor:全てのフィールドコンストラクタ

@AllArgsConstructorは全ての非staticフィールドを引数に持つコンストラクタを自動生成します。

import lombok.AllArgsConstructor;

import java.time.LocalDate;

@AllArgsConstructor
public class ConstructorSample {
    private final String name;
    private int age;
    private final LocalDate birthday;

    // ↓ 自動生成されるコード
    /*
    public ConstructorSample(String name, int age, LocalDate birthday) {
        this.name = name;
        this.age = age;
        this.birthday = birthday;
    }
    */
}

@Data

@Dataは先に紹介した@ToString, @EqualsAndHashCode, @Getter, @Setter, @RuquiredArgsConstructorをまとめたアノテーションとなります。
恐らくlombokの中でこのアノテーションが一番よく使われているのではないかと思います。

import lombok.Data;

import java.time.LocalDate;

@Data
public class DataSample {
    private final String name;
    private int age;
    private final LocalDate birthday;
}

@ToString, @EqualsAndHashCode, @Getter, @Setter, @RuquiredArgsConstructorの設定をカスタマイズしたい場合は、明示的に対象のアノテーションを付与すれば、そちらが優先されます。

まとめ

ここまででLombokの基本的な使い方や代表的な機能の紹介を行ってきました。
長くなりましたので、続きは別の記事に書かせてもらおうと思います。

最後までお読みいただき、ありがとうございました。

コメント

タイトルとURLをコピーしました