はじめに
資格勉強を進める中で、レコードクラスを学ぶ機会がありました。
研修の中で学ぶ機会はなかったものの、結構便利なので今後も使う機会があるかと思い、備忘録としてまとめてみようと思います。
※誤りありましたら、ご指摘いただけますと幸いです。
想定読者
初学者の方
普段Javaを使用している方
レコードクラスとは
Java16より正式に追加された、簡潔かつイミュータブルにデータを保持できるクラスです。
従来は、データを保持する目的においてもクラスを新たに作成し、似通ったクラスを作成していましたが、レコードクラスはこれらボイラープレートコードの作成を軽減してくれます。
※ボイラープレートコード
→定型的で冗長な記述のこと。
実際の使い方
実際の使い方を見ていきましょう。
今回は名前(name)と年齢(age)のみの簡潔なレコードクラスを作成してみます。
public record Person(String name, int age) {}
これだけで完了です。
レコードクラスで保持したいデータをコンポーネントと呼び、ヘッダー内に変数宣言と同様の形で指定すればOKです。(今回はnameとage)
しかしこれだけでは、レコードクラスを用いることで何がなされているのか分からないので、下にレコードクラスで実際に定義されている内容を記述してみます。
public class Person {
private final String name;
private final int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public boolean equals(Object o) {
//等価性判定を行うメソッド
}
public int hashCode() {
//ハッシュ値を生成して返すメソッド
}
public String toString() {
//オブジェクトの文字列情報を返すメソッド
}
}
たったあれだけの簡潔な記述で、
①private finalなメンバ変数
②標準コンストラクタ
③アクセサメソッド(イメージはgetter)
④equals()・hashCode()・toString()メソッド
これらが作成されていることが分かります。
ちなみに、レコードクラス内に新たにメソッドを追加することも可能です。
レコードクラスの特徴
レコードクラスの特徴は、大きく2つあります。
①イミュータブル
コンポーネントの値はfinalが付き、定数として管理されます。よって後から値の変更はできない、イミュータブルなオブジェクトとなります。
getterの役割を担うアクセサメソッドは存在しますが、setterがないのは、定数であるが故に後から値の変更がなされないためです。
②継承不可
レコードクラスは、java.lang.Recordクラスを継承しておらず、かつ暗黙的にfinalとして扱われるため、他のクラスを継承することはできず、そして他クラスでレコードクラスを継承することもできません。
ちなみに、レコードクラスのスーパークラスであるjava.lang.Recordクラスでは、equals()、hashCode()、toString()がメソッドとして存在しています。
レコードクラスを定義するだけで、上記3メソッド
を使用できるのはそういうわけだったんですね。
※ちなみに、これらのメソッドはオーバーライド可能です。
Recordクラスの公式ドキュメントはコチラから。
レコードクラスのコンストラクタ
レコードクラスを扱う上でもう一つ取り上げたいのがコンストラクタについて。
レコードクラスには、レコードクラスでしか使用できないコンパクトコンストラクタというものがあります。
比較
1, 標準コンストラクタ
public record Person(String name, int age) {
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
こちらは通常のコンストラクタ。
メンバ変数に値をセットしています。
2, コンパクトコンストラクタ
public record Person(String name, int age) {
public Person {
age = age > 0 ? age : 0;
}
}
こちらがコンパクトコンストラクタになります。
通常のコンストラクタとの違いとして、まず引数が不要となっています。
そして、特別な初期化処理以外は自動で初期化処理をしてくれるので、初期化処理が不要となっています。今回はageに特別な初期化処理を行うため記述していますが、nameの記述がありません。nameは自動でメンバ変数に値がセットされます。
今回コンポーネントが2つしか指定していないので良さが伝わりづらいですが、もしもコンポーネントが10個20個と多く存在し、その中の一つだけ特別な初期化処理を施したい、そんなときにコンパクトコンストラクタが活躍します。
まとめ
まだ登場したばかりのレコードクラスですが、記述量が格段に減るため、今後活用されることも増えるのではないかと勝手ながら感じました。
少し知っているだけでもキャッチアップも楽になると思うので、この記事が少しでも参考になれば幸いです!