この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
等価性と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;
}