Skip to content

KotlinでのJavaレコードの使用

_レコード_は、Javaにおける不変なデータを格納するためのクラスです。レコードは固定された値のセット、つまり_レコードコンポーネント_を持ちます。 Javaでは簡潔な構文を持ち、ボイラープレートコードを書く手間を省きます:

java
// Java
public record Person (String name, int age) {}

コンパイラは、java.lang.Recordを継承するfinalクラスを自動的に生成し、以下のメンバーを含みます:

  • 各レコードコンポーネントに対応するprivate finalフィールド
  • 全てのフィールドに対応するパラメータを持つpublicコンストラクタ
  • 構造的等価性を実装するためのメソッド群: equals(), hashCode(), toString()
  • 各レコードコンポーネントを読み取るためのpublicメソッド

レコードはKotlinのデータクラスと非常によく似ています。

KotlinコードからのJavaレコードの使用

Javaで宣言されたコンポーネントを持つレコードクラスは、Kotlinでプロパティを持つクラスを使用するのと同じ方法で利用できます。 レコードコンポーネントにアクセスするには、Kotlinプロパティと同じようにその名前を使用します:

kotlin
val newPerson = Person("Kotlin", 10)
val firstName = newPerson.name

Kotlinでのレコード宣言

Kotlinはデータクラスでのみレコード宣言をサポートしており、データクラスは要件を満たす必要があります。

Kotlinでレコードクラスを宣言するには、@JvmRecordアノテーションを使用します:

@JvmRecordを既存のクラスに適用することは、バイナリ互換性のある変更ではありません。これは、クラスプロパティアクセサーの命名規則を変更します。

kotlin
@JvmRecord
data class Person(val name: String, val age: Int)

このJVM固有のアノテーションは、以下の生成を可能にします:

  • クラスファイル内のクラスプロパティに対応するレコードコンポーネント
  • Javaレコードの命名規則に従って命名されたプロパティアクセサーメソッド

データクラスはequals()hashCode()、およびtoString()メソッドの実装を提供します。

要件

@JvmRecordアノテーションを付けてデータクラスを宣言するには、以下の要件を満たす必要があります:

  • クラスは、JVM 16バイトコードをターゲットとするモジュール(または-Xjvm-enable-previewコンパイラオプションが有効になっている場合は15)になければなりません。
  • 全てのJVMレコードが暗黙的にjava.lang.Recordを継承するため、クラスは(Anyを含む)他のクラスを明示的に継承することはできません。ただし、クラスはインターフェースを実装することはできます。
  • クラスは、対応するプライマリコンストラクタパラメータから初期化されるものを除いて、バッキングフィールドを持つプロパティを宣言できません。
  • クラスは、バッキングフィールドを持つ可変プロパティを宣言できません。
  • クラスはローカルにできません。
  • クラスのプライマリコンストラクタは、クラス自体と同じくらい可視である必要があります。

JVMレコードの有効化

JVMレコードは、生成されるJVMバイトコードのターゲットバージョン16以上を必要とします。

それを明示的に指定するには、GradleまたはMavenjvmTargetコンパイラオプションを使用します。

Experimental

Kotlinでのレコードコンポーネントへのアノテーション

Javaでは、レコードコンポーネント上のアノテーションは、バッキングフィールド、ゲッター、セッター、およびコンストラクタパラメータに自動的に伝播されます。 Kotlinでは、allユースサイトターゲットを使用することで、この動作を再現できます。

allユースサイトターゲットを使用するには、オプトインする必要があります。-Xannotation-target-allコンパイラオプションを使用するか、build.gradle.ktsファイルに以下を追加してください:

kotlin
kotlin {
    compilerOptions {
        freeCompilerArgs.add("-Xannotation-target-all")
    }
}

例:

kotlin
@JvmRecord
data class Person(val name: String, @all:Positive val age: Int)

@JvmRecord@all:と一緒に使用すると、Kotlinは次のようになります:

  • プロパティ、バッキングフィールド、コンストラクタパラメータ、ゲッター、セッターにアノテーションを伝播します。
  • アノテーションがJavaのRECORD_COMPONENTをサポートしている場合、レコードコンポーネントにもアノテーションを適用します。

アノテーションをレコードコンポーネントで機能させる

アノテーションをKotlinプロパティJavaレコードコンポーネントの両方で利用可能にするには、アノテーション宣言に以下のメタアノテーションを追加します:

例:

kotlin
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
@java.lang.annotation.Target(ElementType.CLASS, ElementType.RECORD_COMPONENT)
annotation class exampleClass

これで、@ExampleClassをKotlinクラスとプロパティ、ならびにJavaクラスとレコードコンポーネントに適用できます。

さらなる議論

さらなる技術的な詳細と議論については、JVMレコードの言語プロポーザルを参照してください。