Javaのレコードクラス(record)を徹底解説!データクラスを1行で書く方法

docs

皆さん、前回の記事でJavaの基本的なクラスについて学んだよね。

クラスとオブジェクトの概念 – オブジェクト指向の入り口 | ToolDocs

今回は、そんなクラスの中でも**「データだけをシンプルに扱いたい!」ってときに超便利なレコードクラス**について解説していくよ。

「え、データクラスって何?」って思った人もいるかもしれないね。簡単に言うと、名前とか年齢とか、**「いくつかの情報をひとまとまりとして扱いたい」**ときに使うのがデータクラス。例えば、ユーザー情報を扱うなら「ユーザーID」「ユーザー名」「メールアドレス」なんかをまとめて「ユーザー」ってひとつのクラスにしたいよね。

レコードクラスってなんだ?

Javaでデータクラスを作る時、今まではこんな感じで書いてたの覚えてるかな?

Java

class User {
    private final int id;
    private final String name;
    private final String email;

    public User(int id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getEmail() {
        return email;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id && name.equals(user.name) && email.equals(user.email);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, name, email);
    }

    @Override
    public String toString() {
        return "User{" +
               "id=" + id +
               ", name='" + name + '\'' +
               ", email='" + email + '\'' +
               '}';
    }
}

どう?めちゃくちゃコード量が多いよね?こんなに書くのは大変だし、正直めんどくさい!

でも、Java 16から導入されたレコードクラスを使えば、これがびっくりするくらいシンプルになるんだ。レコードクラスは、主にデータを保持するためだけのクラスを、もっと簡単に書けるように作られた特別なクラスなんだ。

じゃあ、さっきのUserクラスをレコードクラスで書いてみよう。

Java

record User(int id, String name, String email) {
    // コンストラクタやゲッターなどは自動で生成される!
}

見て!たった1行で書けちゃった!

レコードクラスを使うと、以下のものが自動で生成されるんだ。

  • すべてのフィールドを引数に持つコンストラクタ
  • 各フィールドのゲッターメソッドgetId(), getName()のように、フィールド名と同じ名前のメソッドになる)
  • equals()メソッド(オブジェクトの比較に使うやつね)
  • hashCode()メソッド(ハッシュ値を計算するやつ)
  • toString()メソッド(オブジェクトの中身を文字列で表示するやつ)

これらを自分で書く手間がなくなるから、コード量が大幅に減って、読みやすく、間違いも減るんだ。まさに**「データクラス作成の救世主」**って感じだよね!

レコードクラスを使ってみよう!

実際にレコードクラスを使ってみるよ。さっきのUserレコードを使ってみよう。

Java

public class RecordExample {
    public static void main(String[] args) {
        // Userレコードのインスタンスを作成
        User user1 = new User(1, "森田", "morita@example.com");

        // ゲッターを使ってデータにアクセス
        System.out.println("ユーザーID: " + user1.id()); // getId()ではなく、id()と呼び出す
        System.out.println("ユーザー名: " + user1.name());
        System.out.println("メールアドレス: " + user1.email());

        // toString()メソッドも自動で生成される
        System.out.println("ユーザー情報: " + user1.toString());

        // equals()メソッドで比較
        User user2 = new User(1, "森田", "morita@example.com");
        User user3 = new User(2, "佐藤", "sato@example.com");

        System.out.println("user1とuser2は同じ?: " + user1.equals(user2)); // trueになる
        System.out.println("user1とuser3は同じ?: " + user1.equals(user3)); // falseになる
    }
}

// Userレコードの定義(同じファイル内に書いてもOK)
record User(int id, String name, String email) { }

出力結果はこんな感じになるよ。

ユーザーID: 1
ユーザー名: 森田
メールアドレス: morita@example.com
ユーザー情報: User[id=1, name=森田, email=morita@example.com]
user1とuser2は同じ?: true
user1とuser3は同じ?: false

どうかな?すごくシンプルに書けてるのがわかるよね!

paizaで実行した結果

レコードクラスのちょっと便利な使い方

レコードクラスは、基本的にデータを保持するだけなんだけど、ちょっとしたメソッドを追加することもできるんだ。

例えば、ユーザーのフルネームを返すメソッドを追加したい場合。

Java

record User(int id, String firstName, String lastName) {
    // コンストラクタをカスタマイズすることもできるけど、基本は自動生成に任せよう
    // 例えば、引数をチェックしたい場合など
    public User {
        if (firstName == null || firstName.isBlank()) {
            throw new IllegalArgumentException("名前に不正な値が含まれています。");
        }
        if (lastName == null || lastName.isBlank()) {
            throw new IllegalArgumentException("名前に不正な値が含まれています。");
        }
    }

    // 新しいメソッドを追加できる
    public String fullName() {
        return firstName + " " + lastName;
    }
}

public class RecordCustomMethodExample {
    public static void main(String[] args) {
        User user = new User(101, "太郎", "山田");
        System.out.println("ユーザー名: " + user.fullName());

        // コンストラクタのチェックも試してみる
        try {
            User invalidUser = new User(102, "", "田中");
        } catch (IllegalArgumentException e) {
            System.out.println("エラー: " + e.getMessage());
        }
    }
}

出力結果はこうなるよ。

ユーザー名: 太郎 山田
エラー: 名前に不正な値が含まれています。

こんな風に、レコードクラスに機能を追加することもできるんだ。ただし、あくまでデータを保持することがメインのクラスだから、複雑なロジックをたくさん追加するのは避けた方がいいよ。複雑な処理が必要なら、通常のクラスを使うことを検討しよう。

paizaで実行した結果

レコードクラスと従来のクラスの比較

ここで、レコードクラスと従来のクラスの比較をもう一度まとめてみよう。

特徴従来のクラスレコードクラス
目的データの保持、振る舞い(メソッド)など、あらゆる用途主にデータをシンプルに保持することに特化
コード量コンストラクタ、ゲッター、equalshashCodetoStringなど、手動で書く必要があり、コード量が多いこれらが自動生成されるため、非常に少ないコード量で済む
可読性コード量が多く、データ構造を把握しにくい場合があるデータ構造がひと目で分かりやすく、可読性が高い
不変性ミュータブル(変更可能)なクラスを書きやすい(もちろんイミュータブルにもできるけど手間がかかる)デフォルトでイミュータブル(不変)であり、安全にデータを扱える
拡張性継承など、高い拡張性を持つ継承はできない(finalクラスとして扱われる)

レコードクラスは、特に**「データの入れ物」**として使う場合に、その真価を発揮するんだ。例えば、データベースから取得したデータを一時的に保持したり、APIのレスポンスデータを表したり、他のメソッドに複数の値をまとめて渡したい場合などに、とっても便利だよ。

一方で、クラスに複雑なロジックや状態を持つ必要がある場合は、従来のクラスを選ぶべきだね。レコードクラスはあくまで「シンプルなデータ」を扱うためのツールだと覚えておこう。

どんな時にレコードクラスを使えばいいの?

  • DTO (Data Transfer Object) として:異なる層間でデータをやり取りする際に、シンプルなデータ構造を定義したいとき。
  • 一時的なデータ構造として:メソッド内で複数の値を一時的にまとめる必要があるとき。
  • マップのキーとしてequals()hashCode()が自動生成されるため、HashMapなどのキーとして使いやすい。
  • タプル(複数の要素をまとめたもの)の代わりとして:複数の値をまとめて返したい場合に、わざわざ新しいクラスを作る手間が省ける。

レコードクラスは、あなたのJavaプログラミングをより効率的で、より読みやすいものに変えてくれる強力なツールなんだ。ぜひ積極的に使ってみてね!


まとめ

今回はJavaのレコードクラスについて解説したよ。

  • レコードクラスは、データをシンプルに保持するための特別なクラス
  • 従来のクラスに比べて、コンストラクタ、ゲッター、equals()hashCode()toString()が自動生成されるため、コード量が大幅に削減される
  • これにより、可読性が向上し、バグのリスクも減る
  • 主にDTOや一時的なデータ構造など、**「データの入れ物」**として使うと便利

レコードクラスを使いこなして、もっと効率的にJavaプログラミングを楽しもう!

今回の記事で、レコードクラスの便利さが伝わったかな?もし疑問に思ったことや、もっと知りたいことがあったら、ぜひコメントで教えてね!

コメント

タイトルとURLをコピーしました