Rec-01: Record の基本
Java 16 で正式導入された record は、 データを保持するためのクラス(DTO・値オブジェクト)を簡潔に書くための仕組みです。toString・equals・hashCode を自動生成します。
record とは何か
API のレスポンスや設定値など「値を保持するためだけのクラス」を作るとき、 従来は final フィールド・コンストラクタ・ゲッター・toString・equals・hashCode をすべて手書きする必要がありました。 record を使うと1行の宣言でこれらをすべて自動生成できます。
record が自動生成するもの
- コンポーネントアクセサ:
name()・age()のようなゲッターメソッド(getプレフィックスなし) - コンストラクタ: すべてのフィールドを引数に取る標準コンストラクタ
- toString():
Person[name=田中太郎, age=25]形式 - equals(): すべてのフィールドの値が同じなら等価と判定
- hashCode(): すべてのフィールドをもとにハッシュ値を生成
record の制約
- フィールドは暗黙的に
final— 作成後に値を変更できません(イミュータブル) - 他のクラスを継承できません(暗黙的に
finalクラス) - インターフェースは実装できます
- メソッドの追加は可能です
サンプルコード
Java 8 では record が使えないため、toString / equals / hashCode をすべて手書きで実装する必要があります。Java 16+ に移行すると record の1行宣言でこれらをすべて自動生成できます。
よくあるミス・注意点
⚠️ record のフィールドは変更不可(セッターは存在しない)
record のフィールドは暗黙的に final です。 作成後に値を変更する setName() のようなメソッドを追加しようとしてもコンパイルエラーになります。 値を変更したい場合は新しい record インスタンスを作成してください。 例えば名前だけ変えたい場合は new Person("別の名前", person.age()) のようにします。
⚠️ record は継承できない(final 扱い)
record は暗黙的に final クラスとして扱われるため、 他のクラスが record を継承することはできません。また、record 自身も他のクラスを継承できません(java.lang.Record を除く)。 共通の振る舞いを持たせたい場合は、インターフェースを実装する方法を使いましょう。
テストする観点
- 同じ値を持つ record 同士が
equals()で等価(true)であること - 異なる値を持つ record が
equals()で非等価(false)であること - 同じ値の record が同じ
hashCode()を返すこと(HashMap のキーとして使える) - コンパクトコンストラクタのバリデーションが正しく動作すること(境界値: 年齢 0、150 は正常、-1 と 151 は例外)
toString()がPerson[name=..., age=...]形式で出力されること- record 内のメソッド(area()・perimeter())が正しく計算されること