4 record

JDK 14では、新しい種類の型宣言であるrecordが導入されています。列挙のように、recordは制限付きのクラス形式です。これは、プレーン・データ・キャリア(変更されないデータ、およびコンストラクタやアクセサなどの最も基本的なメソッドのみを含むクラス)に最適です。

注意:

これは、設計、仕様および実装は完了しているが、永続的でないプレビュー機能であり、将来のJDKリリースでは別の形式で存在するか、完全になくなる可能性があることを意味します。プレビュー機能が含まれているコードをコンパイルして実行するには、追加のコマンド行オプションを指定する必要があります。「プレビュー機能」を参照してください。

recordに関する背景情報は、JEP 359を参照してください。

次のクラス定義について考えてみます。

final class Rectangle implements Shape {
    final double length;
    final double width;
    
    public Rectangle(double length, double width) {
        this.length = length;
        this.width = width;
    }
    
    double length() { return length; }
    double width() { return width; }
}

これには次の機能があります。

  • そのすべてのメンバーがfinalと宣言されます
  • コンストラクタRectangle(double length, double width)、および2つのアクセサlength()width()で構成されるメソッドのみ

このクラスはrecordで表すことができます:

record Rectangle(float length, float width) { }

recordは、名前(この例ではRectangle)とrecordのコンポーネントのリスト(この例ではfloat lengthfloat width)で構成されます。

recordでは、次のメンバーが自動的に取得されます:

  • 各コンポーネントのプライベートのfinalフィールド
  • 名前とコンポーネントのタイプが同じである各コンポーネントのパブリックの読取りアクセサ・メソッド。この例では、Rectangle::length()Rectangle::width()がこれらのメソッドに当たります
  • recordコンポーネントのリストから署名が導出されるパブリック・コンストラクタ。コンストラクタにより、対応する引数の各プライベート・フィールドが初期化されます。
  • equals()およびhashCode()メソッドの実装(2つのrecordのタイプと対応するrecordコンポーネントが等しい場合、その2つが等しいことを指定します)
  • toString()メソッドの実装(すべてのrecordのコンポーネントとその名前の文字列表現が含まれます)

コンパクトなコンストラクタ

recordのコンストラクタでプライベート・フィールドの初期化以上のことを実行する場合は、recordにカスタムのコンストラクタを定義できます。ただし、クラスのコンストラクタとは違い、recordのコンストラクタには正式なパラメータ・リストがありません。これをコンパクトなコンストラクタと呼びます。

たとえば、次のrecord、HelloWorldには、messageというフィールドが1つあります。そのカスタム・コンストラクタでObjects.requireNonNull(message)がコールされ、これによって、messageフィールドがnull値で初期化された場合に、NullPointerExceptionをスローすることが指定されます。(recordのカスタム・コンストラクタでは、引き続きrecordのプライベート・フィールドが初期化されます。)

record HelloWorld(String message) {
    public HelloWorld {
        java.util.Objects.requireNonNull(message);
    }
}

recordの制限事項

recordの使用に関する制限事項は次のとおりです:

  • recordはクラスを拡張できません
  • recordで、(recordコンポーネント・リストのコンポーネントに対応するプライベートのfinalフィールド以外の)インスタンス・フィールドを宣言することはできません。宣言するその他のフィールドは、staticにする必要があります
  • recordはabstractにできません。暗黙的にfinalです
  • recordのコンポーネントは暗黙的にfinalです

これらの制限事項を除けば、recordは通常のクラスと同様に動作します:

  • クラスの中に宣言できます。ネストしたrecordは暗黙的にstaticです
  • 汎用のrecordを作成できます
  • recordはインタフェースを実装できます
  • recordは、newキーワードでインスタンス化します
  • recordのボディのstaticメソッド、staticフィールド、staticイニシャライザ、コンストラクタ、インスタンス・メソッドおよびネストされた型を宣言できます
  • recordおよびrecordの個々のコンポーネントに注釈を付けることができます

API関連のrecord

クラスjava.lang.Classには、recordに関連する次の2つの新しいメソッドがあります:

  • RecordComponent[] getRecordComponents(): recordのコンポーネントに対応するjava.lang.reflect.RecordComponentオブジェクトの配列を返します。
  • boolean isRecord(): クラスがrecordとして宣言された場合にtrueを返すことを除き、isEnum()に似ています。