24
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Javaのレコードクラス

Last updated at Posted at 2023-01-10

記事の目的

DDD(ドメイン駆動設計)では値オブジェクトはイミュータブルであることが求められる。
エンティティオブジェクトも可能であればイミュータブルとすべきである。

レコードクラスはイミュータブルであることが強制できるので、DDDと相性が良い。

DDDに限らず、オブジェクト指向でプログラミングするのであれば、予期せぬオブジェクトの状態変化でつまらないバグにハマることも無くなるので、オブジェクトは極力イミュータブルになるようにしたほうが良いと思っている。

世の中にはクラスに無条件かつ盲目的にgetter/setterをつくる思考停止なプログラミングが溢れていて、Lombokのようなライブラリがそのような悪いプログラミングの量産に拍車をかけている気がする。
「Lombokイコールすべて悪」とは言わないが、なぜそのフィールドがprivateなのか、本当にsetterが必要なのかを考えること無く、なんとなく動く(だけど危うい)プログラムがラクに書けてしまうので、少なくとも自分の携わるプロジェクトではLombokは利用禁止にしている。

Java16から正式実装されたレコードクラスを積極的に使うことで、少なくともイミュータブルであることが保証できるし、Lombokのようなライブラリを使わなくても、言語レベルでシンプル且つ安全なクラスが作れるようになったのでこの記事で基本的な書き方を扱う。

レコードクラスの効能

  • フィールドが private finalで強制されオブジェクトがイミュータブルになる
  • コンストラクタ、toString、equqls、hashCode 各メソッドが自動実装されコードがシンプルになるため、本当に必要な業務ロジックに注目できる

前提

Java16以降(Java14でプレビュー版)

本題

一般的なValueObjectを従来のクラスとレコードクラスそれぞれで書いてみる

普通のJavaクラス

import java.util.Objects;

public final class Title {

    private final String value;

    public Title(String value) {
        this.value = value;
    }

    public String value() {
        return value;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) return true;
        if (obj == null || obj.getClass() != this.getClass()) return false;
        var that = (Title) obj;
        return Objects.equals(this.value, that.value);
    }

    @Override
    public int hashCode() {
        return Objects.hash(value);
    }

    @Override
    public String toString() {
        return "Title[" +
                "value=" + value + ']';
    }
}

上記と同義のレコードクラス

超シンプルになる

public record Title(
    String value
) {
}

コンストラクタの上書きもできる

public record Title(
    String value
) {

    public Title(String value){
        this.value = value + "hoge";
    }
}

Bean Validationもできる

import javax.validation.constraints.NotEmpty;

public record Title(
    @NotEmpty(message = "タイトルを入力してください")
    String value
) {
}

勿論メソッドも実装できる

public record Title(
    String value
) {

    public int length() {
        return this.value.length();
    }
}
24
15
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?