[Java]Lombokを使って等価性の対象フィールドを制御する

2021.03.29

等価性とLombok

Lombokはコードの自動生成によってJavaの開発を支援するライブラリです。例えばフィールドにアノテーションを指定すると対応するgetterやsetterをコンパイル時に自動生成してくれます。煩雑なコードを省略できるので、うまく利用すればコード全体の見通しを良くすることができます。

Javaのインスタンスに対して等価性(equality)を扱いたい場合、そのクラスに対して equals()hashCode()を実装する必要があります。Lombokでは @EqualsAndHashCode をクラスに指定することでこの実装を自動生成させることができます。

以下の例では、Lombokを使ってRecordクラス実装し、等価性に関するテストを行っています。

// Record.java
package example;

import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;

@EqualsAndHashCode
@RequiredArgsConstructor
public class Record {
    private final String code;

    private final String name;

    private final Long createTimestamp;

    private final Long updateTimestamp;
}
// RecordTest.java
package example;

import org.junit.jupiter.api.Test;

import java.time.Instant;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class RecordTest {
    @Test
    void testRecordEquality() throws Exception {
        var now = Instant.now().toEpochMilli();

        var record1 = new Record("id", "name", now, now);
        var record2 = new Record("id", "name", now, now);

        assertTrue(record1.equals(record2));
    }
}

フィールドを等価性判定の対象から外す

equals()hashCode() を実装する際、クラスが持つフィールドのうちどれを対象とするか(あるいはしないか)という判断は実装者に委ねられます。上記の Record クラスを例にすると、id, name はRecordを表現する情報であるのに対して createTimestamp, updateTimestamp はメタ情報なので等価性判定の対象から外すという判断もできます。

このように判定の対象となるフィールドを制御したい場合、Lombokでは判定から除外するフィールドを指定するパターンと判定の対象となるフィールドを指定するパターンがあります。

除外するフィールドを指定する場合

フィールドを明示的に除外する場合、フィールドに対して @EqualsAndHashCode.Exclude を付与します。

// Record.java
package example;

import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;

@EqualsAndHashCode
@RequiredArgsConstructor
public class Record {
    private final String code;

    private final String name;

    @EqualsAndHashCode.Exclude
    private final Long createTimestamp;

    @EqualsAndHashCode.Exclude
    private final Long updateTimestamp;
}

対象フィールドを指定する場合

対象フィールドを指定する場合は、クラスに対して @EqualsAndHashCode(onlyExplicitlyIncluded = true) を指定した上で、フィールドに @EqualsAndHashCode.Include を付与します。

package example;

import lombok.EqualsAndHashCode;
import lombok.RequiredArgsConstructor;

@EqualsAndHashCode(onlyExplicitlyIncluded = true)
@RequiredArgsConstructor
public class Record {

    @EqualsAndHashCode.Include
    private final String code;

    @EqualsAndHashCode.Include
    private final String name;

    private final Long createTimestamp;

    private final Long updateTimestamp;
}

参考