[Java]Lombokを使って等価性の対象フィールドを制御する
等価性と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; }