Java には、他の言語でよく実装されている、複数の値を返す タプル(Tuple) が実装されていません。そのため、これまで Object の配列に複数の値を設定して返すか、タプル(Tuple) のような機能を持つクラスを自作する方法がとられていました。
Java 14 では、Recordクラスが新たに追加され、単純な値を複数持つようなクラスを少ないコードで書くことが可能になりました。これ利用することで、他のプログラミング言語にあるようなタプル(Tuple) のようなものを、Javaでも実現できるようになりました。
Record(レコード)とは
前述のように、Record は Java 14で追加された新機能で、Record の機能を一言で言えば、単純なドメイン・クラス(値を持つプロパティのみが宣言されたクラス)を、少ないコード量で作成できるクラスです。
これまでのドメイン・クラス
Record 登場以前のこれまでの Java では、単純なドメイン・クラスを定義するだけでも、以下のような退屈なコードをいくつも記述必要がありました。
// ユーザの氏名,年齢を持つドメイン・クラス
public class User {
private String name;
private int age;
public User (String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
//2つのオブジェクトを比較し、すべての値が同じか判定するコード
}
@Override
public int hashCode() {
//このドメインのハッシュ値を計算して返すコード
}
@Override
public String toString() {
return "User{" + "name=" + name + ", age=" + age + '}';
}
}
新しい Record クラスを使ったドメイン・クラス
Record の登場によって、上記のようなドメイン・クラスは、次の Recode クラスとして定義できるようになりました。
public record User(String name,
int age) {}
このように、Recode を使用することで、非常に少ないコードでドメイン・クラスの定義ができます。
Recode クラスを使ってみる
Recodeクラスの使い方について、詳しく見ていきましょう。
構文
Recodeクラスを宣言する時の構文は次の通りです。
public record <クラス名>(フィールドのリスト, ....) {}
Recodeを使う
Recode クラスでは、これまで煩わしかった getter は、Recode では記述する必要がなく自動で生成されます。また、setter は生成されないため、最初に設定した値を後から変更することはできない、オブジェクト不変の性質をもっています。
以下のサンプルコードは、氏名および年齢を持つ User レコードクラスのインスタンスを作成し、設定した値を取り出す例です。
public class Main {
public static void main(String[] args) {
var user = new User("Yamada", 20);
System.out.println("NAME:" + user.name());
System.out.println("AGE:" + user.age());
}
}
record User(
String name,
int age
) {}
従来のドメイン・クラスで値を取り出す際は、getName など、getter の先頭には get がつきましたが、Recode クラスでは getter はフィールド名と同じ名前のメソッドで定義されます。
equals をオーバーライドしなくても同値性の判定ができる
従来のドメイン・クラスでは、同値性の判定は equals メソッドをオーバーライドし、その中で各フィールドの値を比較し、すべて同じかとうかの判定を行うロジックを自前で書く必要がありました。
Recode クラスでは、equals メソッドをオーバーライドしなくても、自動的に各フィールドの内容を比較し、同値性の判定を行ってくれます。
次のサンプルコードは、3つの User レコードのインスタンスを生成し比較を行う例です。
public class Main {
public static void main(String[] args) {
var user1 = new User("Yamada", 20);
var user2 = new User("Suzuki", 20);
var user3 = new User("Yamada", 20);
System.out.println("user1 = user2:" + user1.equals(user2));
System.out.println("user1 = user3:" + user1.equals(user3));
System.out.println("user2 = user3:" + user2.equals(user3));
}
}
【出力結果】
user1 = user2:false
user1 = user3:true
user2 = user3:false
このように、各フィールドの値が全て同じであれば、equals の結果が true になっていることが分かります。
toString() で各フィールドの内容が出力できる
これは、デバッグ時に役立つ機能ですが、Recode クラスの toString()メソッドを呼び出すと、各フィールドの内容を繋げた1つの文字列を返してくれます。
プログラムのバグは、何も if や for などのロジックに問題があるだけでなく、扱うデータに問題があることも多々あります。そうした時に、フィールドの内容を出力する toString() メソッドがあると、簡単に調査ができて便利です。
var user = new User("Yamada", 20);
System.out.println(user.toString());
【出力結果】
User[name=Yamada, age=20]
まとめ
Java 14 で新たに追加された Recode クラスの使い方を解説してきました。
Recode クラスは、これまで煩わしかったドメイン・クラスの作成から解放され、本来のロジックの記述に集中でき、さらには、タプル(Tuple) のような使い方もできるため、是非覚えておきましょう。
上のドメイン・クラスの定義の内、equals, hashCode, toString の宣言は必須ではありませんが、オブジェクト同値性の確認や、その同値性や検索処理の効率化、デバック時の視認性の観点から、これらのメソッドをオーバーライドすることが推奨されています。