Kotlin 2.2.0の新機能
Kotlin 2.2.0がリリースされました!主なハイライトは以下の通りです。
- 言語: コンテキストパラメータなど、プレビュー段階の新言語機能が追加されました。ガード条件、非ローカルな
break
とcontinue
、複数ドル記号による文字列補間など、以前実験的だった機能のいくつかは安定版になりました。 - Kotlinコンパイラ: コンパイラの警告の一元管理。
- Kotlin/JVM: インターフェース関数のデフォルトメソッド生成の変更点。
- Kotlin/Native: LLVM 19とメモリ消費量の追跡および調整のための新機能。
- Kotlin/Wasm: Wasmターゲットの分離とプロジェクトごとのBinaryen設定機能。
- Kotlin/JS:
@JsPlainObject
インターフェース用に生成されるcopy()
メソッドの修正。 - Gradle: Kotlin Gradleプラグインにバイナリ互換性検証が組み込まれました。
- 標準ライブラリ: Base64およびHexFormat APIの安定化。
- ドキュメント: ドキュメントに関するアンケートを開始しました。また、Kotlinドキュメントに大幅な改善が行われました。
Kotlin Language Evolutionチームが新機能について議論し、質問に答えるこのビデオもご覧ください。
IDEサポート
2.2.0をサポートするKotlinプラグインは、IntelliJ IDEAおよびAndroid Studioの最新バージョンに同梱されています。 IDEのKotlinプラグインを更新する必要はありません。 必要なのは、ビルドスクリプトでKotlinのバージョンを2.2.0に変更するだけです。
詳細は新しいリリースへのアップデートを参照してください。
言語
このリリースでは、ガード条件、非ローカルなbreak
とcontinue
、複数ドル記号による文字列補間が安定版に昇格しました。 さらに、コンテキストパラメータやコンテキスト依存の解決などのいくつかの機能がプレビューとして導入されました。
コンテキストパラメータのプレビュー
コンテキストパラメータを使用すると、関数とプロパティは、周囲のコンテキストで暗黙的に利用可能な依存関係を宣言できます。
コンテキストパラメータを使用すると、サービスや依存関係など、共有され、関数呼び出しのセット間でめったに変更されない値を手動で渡す必要がなくなります。
コンテキストパラメータは、コンテキストレシーバと呼ばれる以前の実験的な機能を置き換えます。コンテキストレシーバからコンテキストパラメータに移行するには、ブログ記事で説明されているように、IntelliJ IDEAの支援機能を使用できます。
主な違いは、コンテキストパラメータが関数の本体にレシーバとして導入されない点です。結果として、コンテキストが暗黙的に利用可能だったコンテキストレシーバとは異なり、コンテキストパラメータの名前を使用してそのメンバーにアクセスする必要があります。
Kotlinのコンテキストパラメータは、簡素化された依存性注入、改善されたDSL設計、およびスコープ付き操作を通じて、依存関係の管理において大幅な改善をもたらします。詳細については、この機能のKEEPを参照してください。
コンテキストパラメータの宣言方法
context
キーワードの後にname: Type
の形式のパラメータのリストを続けることで、プロパティや関数にコンテキストパラメータを宣言できます。以下は、UserService
インターフェースへの依存関係を持つ例です。
// UserServiceはコンテキストで必要な依存関係を定義します
interface UserService {
fun log(message: String)
fun findUserById(id: Int): String
}
// コンテキストパラメータを持つ関数を宣言します
context(users: UserService)
fun outputMessage(message: String) {
// コンテキストからlogを使用します
users.log("Log: $message")
}
// コンテキストパラメータを持つプロパティを宣言します
context(users: UserService)
val firstUser: String
// コンテキストからfindUserByIdを使用します
get() = users.findUserById(1)
コンテキストパラメータ名として_
を使用できます。この場合、パラメータの値は解決に利用できますが、ブロック内で名前によってアクセスすることはできません。
// コンテキストパラメータ名として"_"を使用
context(_: UserService)
fun logWelcome() {
// UserServiceから適切なlog関数を見つけます
outputMessage("Welcome!")
}
コンテキストパラメータを有効にする方法
プロジェクトでコンテキストパラメータを有効にするには、コマンドラインで以下のコンパイラオプションを使用します。
-Xcontext-parameters
または、GradleビルドファイルのcompilerOptions {}
ブロックに追加します。
// build.gradle.kts
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xcontext-parameters")
}
}
-Xcontext-receivers
と-Xcontext-parameters
の両方のコンパイラオプションを同時に指定するとエラーになります。
フィードバックにご協力ください
この機能は、今後のKotlinリリースで安定化され、改善される予定です。 課題トラッカーYouTrackへのフィードバックをお待ちしております。
コンテキスト依存の解決のプレビュー
Kotlin 2.2.0は、コンテキスト依存の解決のプレビュー版実装を導入します。
以前は、型がコンテキストから推論できる場合でも、enumエントリまたはsealedクラスのメンバーの完全な名前を記述する必要がありました。 例:
enum class Problem {
CONNECTION, AUTHENTICATION, DATABASE, UNKNOWN
}
fun message(problem: Problem): String = when (problem) {
Problem.CONNECTION -> "connection"
Problem.AUTHENTICATION -> "authentication"
Problem.DATABASE -> "database"
Problem.UNKNOWN -> "unknown"
}
現在、コンテキスト依存の解決により、期待される型が既知であるコンテキストでは、型名を省略できます。
enum class Problem {
CONNECTION, AUTHENTICATION, DATABASE, UNKNOWN
}
// 問題の既知の型に基づいてenumエントリを解決します
fun message(problem: Problem): String = when (problem) {
CONNECTION -> "connection"
AUTHENTICATION -> "authentication"
DATABASE -> "database"
UNKNOWN -> "unknown"
}
コンパイラは、このコンテキストの型情報を使用して、正しいメンバーを解決します。この情報には、とりわけ以下が含まれます。
when
式の対象- 明示的な戻り値の型
- 宣言された変数型
- 型チェック (
is
) およびキャスト (as
) - sealedクラス階層の既知の型
- パラメータの宣言された型
コンテキスト依存の解決は、関数、パラメータを持つプロパティ、またはレシーバを持つ拡張プロパティには適用されません。
プロジェクトでコンテキスト依存の解決を試すには、コマンドラインで以下のコンパイラオプションを使用します。
-Xcontext-sensitive-resolution
または、GradleビルドファイルのcompilerOptions {}
ブロックに追加します。
// build.gradle.kts
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xcontext-sensitive-resolution")
}
}
私たちは、今後のKotlinリリースでこの機能を安定化させ、改善していく予定です。課題トラッカーYouTrackへのフィードバックをお待ちしております。
アノテーション使用サイトターゲット機能のプレビュー
Kotlin 2.2.0は、アノテーションの使用サイトターゲットとの連携をより便利にするいくつかの機能を導入します。
プロパティの`@all`メタターゲット
Kotlinでは、使用サイトターゲットとして知られる、宣言の特定の箇所にアノテーションを付加できます。 しかし、各ターゲットに個別にアノテーションを付けるのは複雑でエラーが発生しやすいものでした。
data class User(
val username: String,
@param:Email // コンストラクタパラメータ
@field:Email // バッキングフィールド
@get:Email // ゲッターメソッド
@property:Email // Kotlinプロパティ参照
val email: String,
) {
@field:Email
@get:Email
@property:Email
val secondaryEmail: String? = null
}
これを簡素化するために、Kotlinはプロパティ用の新しい@all
メタターゲットを導入します。 この機能は、コンパイラに、プロパティの関連するすべての箇所にアノテーションを適用するように指示します。@all
を使用すると、アノテーションは以下に適用しようとします。
param
: プライマリコンストラクタで宣言されている場合、コンストラクタパラメータ。property
: Kotlinプロパティ自体。field
: 存在する場合、バッキングフィールド。get
: ゲッターメソッド。set_param
: プロパティがvar
として定義されている場合、セッターメソッドのパラメータ。RECORD_COMPONENT
: クラスが@JvmRecord
である場合、アノテーションはJavaレコードコンポーネントに適用されます。この動作は、Javaがレコードコンポーネントのアノテーションを処理する方法を模倣しています。
コンパイラは、指定されたプロパティのターゲットにのみアノテーションを適用します。
以下の例では、@Email
アノテーションは各プロパティの関連するすべてのターゲットに適用されます。
data class User(
val username: String,
// @Emailをparam、property、field、
// get、set_param(varの場合)に適用します
@all:Email val email: String,
) {
// @Emailをproperty、field、およびgetterに適用します
// (コンストラクタにはないためparamなし)
@all:Email val secondaryEmail: String? = null
}
プライマリコンストラクタの内外を問わず、任意のプロパティで@all
メタターゲットを使用できます。ただし、複数のアノテーションで@all
メタターゲットを使用することはできません。
この新機能は、構文を簡素化し、一貫性を確保し、Javaレコードとの相互運用性を向上させます。
プロジェクトで@all
メタターゲットを有効にするには、コマンドラインで以下のコンパイラオプションを使用します。
-Xannotation-target-all
または、GradleビルドファイルのcompilerOptions {}
ブロックに追加します。
// build.gradle.kts
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xannotation-target-all")
}
}
この機能はプレビュー段階です。問題が発生した場合は、課題トラッカーYouTrackまでご報告ください。 @all
メタターゲットの詳細については、このKEEP提案を参照してください。
使用サイトアノテーションターゲットの新しいデフォルトルール
Kotlin 2.2.0は、パラメータ、フィールド、プロパティにアノテーションを伝播するための新しいデフォルトルールを導入します。 以前はアノテーションがデフォルトでparam
、property
、field
のいずれか1つにのみ適用されていましたが、現在はアノテーションに期待されるものとより一致するようになりました。
複数の適用可能なターゲットがある場合、以下のように1つ以上が選択されます。
- コンストラクタパラメータターゲット (
param
) が適用可能な場合、それが使用されます。 - プロパティターゲット (
property
) が適用可能な場合、それが使用されます。 - フィールドターゲット (
field
) が適用可能でproperty
が適用可能でない場合、field
が使用されます。
複数のターゲットがあり、param
、property
、field
のいずれも適用できない場合、アノテーションはエラーになります。
この機能を有効にするには、GradleビルドファイルのcompilerOptions {}
ブロックに追加します。
// build.gradle.kts
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xannotation-default-target=param-property")
}
}
または、コンパイラのコマンドライン引数を使用します。
-Xannotation-default-target=param-property
古い動作を使用したい場合は、次のことができます。
特定のケースでは、例えば
@Annotation
の代わりに@param:Annotation
を使用するなど、必要なターゲットを明示的に定義します。プロジェクト全体では、Gradleビルドファイルでこのフラグを使用します。
kotlin// build.gradle.kts kotlin { compilerOptions { freeCompilerArgs.add("-Xannotation-default-target=first-only") } }
この機能はプレビュー段階です。問題が発生した場合は、課題トラッカーYouTrackまでご報告ください。 アノテーション使用サイトターゲットの新しいデフォルトルールの詳細については、このKEEP提案を参照してください。
ネストされた型エイリアスのサポート
以前は、型エイリアスはKotlinファイルのトップレベルでのみ宣言できました。これは、内部またはドメイン固有の型エイリアスでさえ、使用されるクラスの外に存在する必要があることを意味していました。
2.2.0以降、外側のクラスから型パラメータをキャプチャしない限り、他の宣言内で型エイリアスを定義できます。
class Dijkstra {
typealias VisitedNodes = Set<Node>
private fun step(visited: VisitedNodes, ...) = ...
}
ネストされた型エイリアスには、型パラメータを参照できないなど、いくつかの追加の制約があります。全ルールセットについてはドキュメントを参照してください。
ネストされた型エイリアスは、カプセル化の向上、パッケージレベルの煩雑さの軽減、内部実装の簡素化により、よりクリーンで保守しやすいコードを可能にします。
ネストされた型エイリアスを有効にする方法
プロジェクトでネストされた型エイリアスを有効にするには、コマンドラインで以下のコンパイラオプションを使用します。
-Xnested-type-aliases
または、GradleビルドファイルのcompilerOptions {}
ブロックに追加します。
// build.gradle.kts
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xnested-type-aliases")
}
}
フィードバックを共有する
ネストされた型エイリアスは現在ベータ版です。問題が発生した場合は、課題トラッカーYouTrackまでご報告ください。この機能の詳細については、このKEEP提案を参照してください。
安定版機能: ガード条件、非ローカルなbreak
とcontinue
、および複数ドル記号による文字列補間
Kotlin 2.1.0では、いくつかの新言語機能がプレビュー段階で導入されました。 このリリースで以下の言語機能が安定版になったことをお知らせします。
Kotlinの言語設計機能と提案の全リストを参照してください。
Kotlinコンパイラ: コンパイラの警告の一元管理
Kotlin 2.2.0は、新しいコンパイラオプション-Xwarning-level
を導入します。これは、Kotlinプロジェクトでコンパイラの警告を一元的に管理するための統一された方法を提供することを目的としています。
以前は、-nowarn
ですべての警告を無効にする、-Werror
ですべての警告をコンパイルエラーにする、または-Wextra
で追加のコンパイラチェックを有効にするなど、一般的なモジュール全体にわたるルールのみを適用できました。特定の警告に対して調整する唯一のオプションは-Xsuppress-warning
オプションでした。
この新しいソリューションにより、一般的なルールを上書きし、特定の診断を一貫した方法で除外できます。
適用方法
新しいコンパイラオプションは以下の構文を持ちます。
-Xwarning-level=DIAGNOSTIC_NAME:(error|warning|disabled)
error
: 指定された警告をエラーに昇格させます。warning
: 警告を出力し、デフォルトで有効になります。disabled
: 指定された警告をモジュール全体で完全に抑制します。
この新しいコンパイラオプションでは、_警告_の重要度レベルのみを設定できることに注意してください。
ユースケース
新しいソリューションを使用すると、一般的なルールと特定のルールを組み合わせることで、プロジェクトでの警告レポートをより詳細に調整できます。 ユースケースを選択してください:
警告の抑制
コマンド | 説明 |
---|---|
-nowarn | コンパイル中のすべての警告を抑制します。 |
-Xwarning-level=DIAGNOSTIC_NAME:disabled | 指定された警告のみを抑制します。 |
-nowarn -Xwarning-level=DIAGNOSTIC_NAME:warning | 指定された警告を除き、すべての警告を抑制します。 |
警告をエラーに昇格
コマンド | 説明 |
---|---|
-Werror | すべての警告をコンパイルエラーに昇格させます。 |
-Xwarning-level=DIAGNOSTIC_NAME:error | 指定された警告のみをエラーに昇格させます。 |
-Werror -Xwarning-level=DIAGNOSTIC_NAME:warning | 指定された警告を除き、すべての警告をエラーに昇格させます。 |
追加のコンパイラ警告を有効にする
コマンド | 説明 |
---|---|
-Wextra | trueの場合に警告を出力する、すべての追加の宣言、式、型コンパイラチェックを有効にします。 |
-Xwarning-level=DIAGNOSTIC_NAME:warning | 指定された追加のコンパイラチェックのみを有効にします。 |
-Wextra -Xwarning-level=DIAGNOSTIC_NAME:disabled | 指定されたものを除き、すべての追加チェックを有効にします。 |
警告リスト
一般的なルールから除外したい警告が多数ある場合、@argfile
を介して別のファイルにそれらをリストできます。
フィードバックにご協力ください
新しいコンパイラオプションはまだ実験的です。問題が発生した場合は、課題トラッカーYouTrackまでご報告ください。
Kotlin/JVM
Kotlin 2.2.0はJVMに多くのアップデートをもたらします。コンパイラはJava 24バイトコードをサポートし、インターフェース関数のデフォルトメソッド生成に変更を導入します。また、このリリースではKotlinメタデータでのアノテーションの扱いを簡素化し、インライン値クラスとのJava相互運用性を向上させ、JVMレコードへのアノテーション付けのサポートを改善します。
インターフェース関数のデフォルトメソッド生成の変更点
Kotlin 2.2.0以降、インターフェースで宣言された関数は、別途設定されていない限り、JVMのデフォルトメソッドにコンパイルされます。この変更は、Kotlinの、実装を持つインターフェース関数がバイトコードにコンパイルされる方法に影響します。
この動作は、非推奨の-Xjvm-default
オプションを置き換える、新しい安定版コンパイラオプション-jvm-default
によって制御されます。
以下の値を使用して-jvm-default
オプションの動作を制御できます。
enable
(デフォルト): インターフェースにデフォルト実装を生成し、サブクラスとDefaultImpls
クラスにブリッジ関数を含めます。このモードは、古いKotlinバージョンとのバイナリ互換性を維持するために使用します。no-compatibility
: インターフェースにデフォルト実装のみを生成します。このモードでは、互換性ブリッジとDefaultImpls
クラスがスキップされるため、新しいコードに適しています。disable
: インターフェースのデフォルト実装を無効にします。ブリッジ関数とDefaultImpls
クラスのみが生成され、Kotlin 2.2.0より前の動作と一致します。
-jvm-default
コンパイラオプションを設定するには、Gradle Kotlin DSLでjvmDefault
プロパティを設定します。
// build.gradle.kts
kotlin {
compilerOptions {
jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
}
}
Kotlinメタデータにおけるアノテーションの読み書きのサポート
以前は、コンパイルされたJVMクラスファイルからリフレクションまたはバイトコード分析を使用してアノテーションを読み取り、シグネチャに基づいてメタデータエントリに手動で一致させる必要がありました。 このプロセスは、特にオーバーロードされた関数では、エラーが発生しやすかったものでした。
現在、Kotlin 2.2.0では、Kotlinメタデータに格納されたアノテーションの読み取りのサポートが導入されます。
コンパイルされたファイルのメタデータでアノテーションを利用可能にするには、以下のコンパイラオプションを追加します。
-Xannotations-in-metadata
または、GradleビルドファイルのcompilerOptions {}
ブロックに追加します。
// build.gradle.kts
kotlin {
compilerOptions {
freeCompilerArgs.add("-Xannotations-in-metadata")
}
}
このオプションを有効にすると、KotlinコンパイラはJVMバイトコードとともにメタデータにアノテーションを書き込み、kotlin-metadata-jvm
ライブラリからアクセスできるようにします。
このライブラリは、アノテーションにアクセスするための以下のAPIを提供します。
KmClass.annotations
KmFunction.annotations
KmProperty.annotations
KmConstructor.annotations
KmPropertyAccessorAttributes.annotations
KmValueParameter.annotations
KmFunction.extensionReceiverAnnotations
KmProperty.extensionReceiverAnnotations
KmProperty.backingFieldAnnotations
KmProperty.delegateFieldAnnotations
KmEnumEntry.annotations
これらのAPIは実験的です。 オプトインするには、@OptIn(ExperimentalAnnotationsInMetadata::class)
アノテーションを使用します。
Kotlinメタデータからアノテーションを読み取る例を以下に示します。
@file:OptIn(ExperimentalAnnotationsInMetadata::class)
import kotlin.metadata.ExperimentalAnnotationsInMetadata
import kotlin.metadata.jvm.KotlinClassMetadata
annotation class Label(val value: String)
@Label("Message class")
class Message
fun main() {
val metadata = Message::class.java.getAnnotation(Metadata::class.java)
val kmClass = (KotlinClassMetadata.readStrict(metadata) as KotlinClassMetadata.Class).kmClass
println(kmClass.annotations)
// [@Label(value = StringValue("Message class"))]
}
プロジェクトで
kotlin-metadata-jvm
ライブラリを使用している場合、アノテーションをサポートするようにコードをテストおよび更新することをお勧めします。 そうしないと、将来のKotlinバージョンでメタデータ内のアノテーションがデフォルトで有効になったときに、プロジェクトが無効または不完全なメタデータを生成する可能性があります。問題が発生した場合は、課題トラッカーまでご報告ください。
インライン値クラスとのJava相互運用性の改善
Kotlin 2.2.0は、新しい実験的なアノテーション@JvmExposeBoxed
を導入します。このアノテーションは、Javaからインライン値クラスを使用しやすくします。
デフォルトでは、Kotlinはインライン値クラスをアンボックス化された表現を使用するようにコンパイルします。これはパフォーマンスが向上しますが、Javaから使用するのが困難または不可能な場合が多いです。例:
@JvmInline value class PositiveInt(val number: Int) {
init { require(number >= 0) }
}
この場合、クラスがアンボックス化されているため、Javaが呼び出せるコンストラクタがありません。また、Javaがinit
ブロックをトリガーしてnumber
が正であることを保証する方法もありません。
クラスに@JvmExposeBoxed
アノテーションを付けると、KotlinはJavaが直接呼び出せるパブリックコンストラクタを生成し、init
ブロックも実行されることを保証します。
@JvmExposeBoxed
アノテーションは、クラス、コンストラクタ、または関数レベルで適用でき、Javaに公開されるものを細かく制御できます。
例えば、以下のコードでは、拡張関数.timesTwoBoxed()
はJavaからアクセスできません。
@JvmInline
value class MyInt(val value: Int)
fun MyInt.timesTwoBoxed(): MyInt = MyInt(this.value * 2)
MyInt
クラスのインスタンスを作成し、Javaコードから.timesTwoBoxed()
関数を呼び出すことを可能にするには、クラスと関数の両方に@JvmExposeBoxed
アノテーションを追加します。
@JvmExposeBoxed
@JvmInline
value class MyInt(val value: Int)
@JvmExposeBoxed
fun MyInt.timesTwoBoxed(): MyInt = MyInt(this.value * 2)
これらのアノテーションを使用すると、KotlinコンパイラはMyInt
クラス用のJavaからアクセス可能なコンストラクタを生成します。また、値クラスのボックス化された形式を使用する拡張関数のオーバーロードも生成します。結果として、以下のJavaコードが正常に実行されます。
MyInt input = new MyInt(5);
MyInt output = ExampleKt.timesTwoBoxed(input);
公開したいインライン値クラスのすべての部分にアノテーションを付けたくない場合、アノテーションをモジュール全体に効果的に適用できます。この動作をモジュールに適用するには、-Xjvm-expose-boxed
オプションでコンパイルします。このオプションでコンパイルすると、モジュール内のすべての宣言に@JvmExposeBoxed
アノテーションが付いているのと同じ効果があります。
この新しいアノテーションは、Kotlinが値クラスを内部でコンパイルまたは使用する方法を変更せず、既存のコンパイル済みコードはすべて有効なままです。Java相互運用性を向上させる新しい機能を追加するだけです。値クラスを使用するKotlinコードのパフォーマンスには影響しません。
@JvmExposeBoxed
アノテーションは、メンバー関数のボックス化されたバリアントを公開し、ボックス化された戻り値の型を受け取りたいライブラリ作者にとって有用です。これにより、インライン値クラス(効率的だがKotlin専用)とデータクラス(Java互換だが常にボックス化される)のどちらかを選択する必要がなくなります。
@JvmExposedBoxed
アノテーションの動作とそれが解決する問題に関するより詳細な説明については、このKEEP提案を参照してください。
JVMレコードへのアノテーション付けのサポートの改善
KotlinはKotlin 1.5.0以降、JVMレコードをサポートしています。現在、Kotlin 2.2.0は、レコードコンポーネントに対するKotlinのアノテーションの扱いを改善します。特に、JavaのRECORD_COMPONENT
ターゲットとの関連において、改善が見られます。
まず、RECORD_COMPONENT
をアノテーションターゲットとして使用したい場合、Kotlin (@Target
) とJavaのアノテーションを手動で追加する必要があります。これは、Kotlinの@Target
アノテーションがRECORD_COMPONENT
をサポートしていないためです。例:
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
@java.lang.annotation.Target(ElementType.CLASS, ElementType.RECORD_COMPONENT)
annotation class exampleClass
両方のリストを手動で維持するのはエラーが発生しやすいため、Kotlin 2.2.0はKotlinとJavaのターゲットが一致しない場合にコンパイラの警告を導入します。例えば、JavaターゲットリストからElementType.CLASS
を省略すると、コンパイラは次のように報告します。
Incompatible annotation targets: Java target 'CLASS' missing, corresponding to Kotlin targets 'CLASS'.
次に、Kotlinの動作は、レコードでのアノテーションの伝播に関してJavaとは異なります。Javaでは、レコードコンポーネントのアノテーションは自動的にバッキングフィールド、ゲッター、およびコンストラクタパラメータに適用されます。Kotlinはデフォルトではこれを実行しませんが、@all:
使用サイトターゲットを使用してその動作を再現できるようになりました。
例:
@JvmRecord
data class Person(val name: String, @all:Positive val age: Int)
@JvmRecord
を@all:
と組み合わせて使用すると、Kotlinは現在、次のように動作します。
- アノテーションをプロパティ、バッキングフィールド、コンストラクタパラメータ、ゲッターに伝播します。
- アノテーションがJavaの
RECORD_COMPONENT
をサポートしている場合、レコードコンポーネントにもアノテーションを適用します。
Kotlin/Native
2.2.0以降、Kotlin/NativeはLLVM 19を使用します。このリリースでは、メモリ消費量を追跡および調整するために設計されたいくつかの実験的機能も導入します。
オブジェクトごとのメモリ割り当て
Kotlin/Nativeのメモリ割り当てツールは、オブジェクトごとにメモリを予約できるようになりました。場合によっては、これにより厳密なメモリ制限を満たしたり、アプリケーションの起動時のメモリ消費量を削減したりするのに役立つ場合があります。
この新機能は、デフォルトのメモリ割り当てツールの代わりにシステムメモリ割り当てツールを有効にする-Xallocator=std
コンパイラオプションを置き換えるように設計されています。現在、メモリ割り当てを切り替えることなく、バッファリング(割り当てのページング)を無効にできます。
この機能は現在実験的です。 有効にするには、gradle.properties
ファイルで以下のオプションを設定します。
kotlin.native.binary.pagedAllocator=false
問題が発生した場合は、課題トラッカーYouTrackまでご報告ください。
実行時におけるLatin-1エンコード文字列のサポート
Kotlinは現在、JVMと同様に、Latin-1エンコードされた文字列をサポートするようになりました。これは、アプリケーションのバイナリサイズを削減し、メモリ消費量を調整するのに役立つはずです。
デフォルトでは、Kotlinの文字列はUTF-16エンコーディングを使用して格納され、各文字は2バイトで表現されます。場合によっては、これによりソースコードと比較して、バイナリで文字列が2倍のスペースを占めることになり、単純なASCIIファイルからデータを読み取ると、ディスクにファイルを保存するよりも2倍のメモリを消費する可能性があります。
一方、Latin-1 (ISO 8859-1)エンコーディングは、最初の256個のUnicode文字をそれぞれ1バイトで表現します。Latin-1サポートが有効になっている場合、すべての文字がその範囲内にある限り、文字列はLatin-1エンコーディングで格納されます。それ以外の場合は、デフォルトのUTF-16エンコーディングが使用されます。
Latin-1サポートを有効にする方法
この機能は現在実験的です。 有効にするには、gradle.properties
ファイルで以下のオプションを設定します。
kotlin.native.binary.latin1Strings=true
既知の問題
この機能が実験的である限り、cinterop拡張関数String.pin
、String.usePinned
、およびString.refTo
は効率が低下します。それらへの各呼び出しは、自動的な文字列のUTF-16変換をトリガーする可能性があります。
Kotlinチームは、この機能の実装にご協力いただいたGoogleの同僚、特にSonya Valchukに深く感謝いたします。
Kotlinでのメモリ消費量の詳細については、ドキュメントを参照してください。
Appleプラットフォームにおけるメモリ消費量追跡の改善
Kotlin 2.2.0以降、Kotlinコードによって割り当てられたメモリにタグが付けられるようになりました。これは、Appleプラットフォームでのメモリ問題のデバッグに役立ちます。
アプリケーションの高いメモリ使用量を調査する際、Kotlinコードによってどれくらいのメモリが予約されているかを識別できるようになりました。Kotlinの共有メモリは識別子でタグ付けされ、Xcode InstrumentsのVM Trackerなどのツールを通じて追跡できます。
この機能はデフォルトで有効ですが、以下の_すべての_条件が満たされている場合にのみ、Kotlin/Nativeのデフォルトメモリ割り当てツールで利用可能です。
タグ付けが有効であること。メモリには有効な識別子でタグが付けられている必要があります。Appleは240から255の範囲の数値を推奨しており、デフォルト値は246です。
kotlin.native.binary.mmapTag=0
Gradleプロパティを設定すると、タグ付けは無効になります。mmap
による割り当て。アロケータはmmap
システムコールを使用してファイルをメモリにマップする必要があります。kotlin.native.binary.disableMmap=true
Gradleプロパティを設定すると、デフォルトのアロケータはmmap
の代わりにmalloc
を使用します。ページングが有効であること。割り当てのページング(バッファリング)が有効になっている必要があります。
kotlin.native.binary.pagedAllocator=false
Gradleプロパティを設定すると、代わりにメモリはオブジェクトごとに予約されます。
Kotlinでのメモリ消費量の詳細については、ドキュメントを参照してください。
LLVM 16から19へのアップデート
Kotlin 2.2.0では、LLVMをバージョン16から19にアップデートしました。 新しいバージョンには、パフォーマンスの改善、バグ修正、セキュリティアップデートが含まれています。
このアップデートがコードに影響を与えることはないはずですが、何か問題が発生した場合は、課題トラッカーまでご報告ください。
Windows 7ターゲットの非推奨化
Kotlin 2.2.0以降、最小サポートWindowsバージョンがWindows 7からWindows 10に引き上げられました。Microsoftが2025年1月にWindows 7のサポートを終了したため、私たちはこのレガシーターゲットを非推奨とすることを決定しました。
詳細については、ネイティブターゲットのサポートを参照してください。
Kotlin/Wasm
このリリースでは、WasmターゲットのビルドインフラストラクチャがJavaScriptターゲットから分離されました。さらに、プロジェクトまたはモジュールごとにBinaryenツールを設定できるようになりました。
WasmターゲットのビルドインフラストラクチャがJavaScriptターゲットから分離されました
以前は、wasmJs
ターゲットはjs
ターゲットと同じインフラストラクチャを共有していました。その結果、両方のターゲットは同じディレクトリ (build/js
) にホストされ、同じNPMタスクと設定を使用していました。
現在、wasmJs
ターゲットはjs
ターゲットとは分離された独自のインフラストラクチャを持つようになりました。これにより、WasmタスクとタイプをJavaScriptのそれらと区別し、独立した設定を可能にします。
さらに、Wasm関連のプロジェクトファイルとNPM依存関係は、個別のbuild/wasm
ディレクトリに格納されるようになりました。
Wasm用の新しいNPM関連タスクが導入され、既存のJavaScriptタスクはJavaScript専用になりました。
Wasmタスク | JavaScriptタスク |
---|---|
kotlinWasmNpmInstall | kotlinNpmInstall |
wasmRootPackageJson | rootPackageJson |
同様に、新しいWasm固有の宣言が追加されました。
Wasm宣言 | JavaScript宣言 |
---|---|
WasmNodeJsRootPlugin | NodeJsRootPlugin |
WasmNodeJsPlugin | NodeJsPlugin |
WasmYarnPlugin | YarnPlugin |
WasmNodeJsRootExtension | NodeJsRootExtension |
WasmNodeJsEnvSpec | NodeJsEnvSpec |
WasmYarnRootEnvSpec | YarnRootEnvSpec |
これにより、JavaScriptターゲットから独立してWasmターゲットを操作できるようになり、設定プロセスが簡素化されます。
この変更はデフォルトで有効になっており、追加の設定は不要です。
プロジェクトごとのBinaryen設定
Kotlin/Wasmでプロダクションビルドを最適化するために使用されるBinaryenツールは、以前はルートプロジェクトで一度だけ設定されていました。
現在、プロジェクトまたはモジュールごとにBinaryenツールを設定できるようになりました。この変更はGradleのベストプラクティスと整合し、プロジェクト分離のような機能のサポートを強化し、複雑なビルドでのビルドパフォーマンスと信頼性を向上させます。
さらに、必要に応じて、異なるモジュールに対して異なるバージョンのBinaryenを設定することもできます。
この機能はデフォルトで有効です。ただし、カスタムのBinaryen設定がある場合、ルートプロジェクトのみではなく、プロジェクトごとに適用する必要があります。
Kotlin/JS
このリリースでは、@JsPlainObject
インターフェースにおけるcopy()
関数の修正、@JsModule
アノテーションを持つファイルでの型エイリアス、およびその他のKotlin/JS機能が改善されています。
@JsPlainObject
インターフェースにおけるcopy()
の修正
Kotlin/JSにはjs-plain-objects
という実験的なプラグインがあり、@JsPlainObject
でアノテーションされたインターフェースにcopy()
関数を導入しました。copy()
関数を使用してオブジェクトを操作できます。
しかし、copy()
の初期実装は継承と互換性がなく、これにより@JsPlainObject
インターフェースが他のインターフェースを拡張する際に問題を引き起こしました。
プレーンオブジェクトに関する制限を回避するため、copy()
関数はオブジェクト自体からそのコンパニオンオブジェクトに移動されました。
@JsPlainObject
external interface User {
val name: String
val age: Int
}
fun main() {
val user = User(name = "SomeUser", age = 21)
// この構文はもう有効ではありません
val copy = user.copy(age = 35)
// こちらが正しい構文です
val copy = User.copy(user, age = 35)
}
この変更は、継承階層の競合を解決し、曖昧さを解消します。 Kotlin 2.2.0からデフォルトで有効になります。
@JsModule
アノテーションを持つファイルにおける型エイリアスのサポート
以前は、JavaScriptモジュールから宣言をインポートするために@JsModule
でアノテーションされたファイルは、外部宣言にのみ制限されていました。これは、そのようなファイルでtypealias
を宣言できなかったことを意味します。
Kotlin 2.2.0以降、@JsModule
でマークされたファイル内で型エイリアスを宣言できます。
@file:JsModule("somepackage")
package somepackage
typealias SomeClass = Any
この変更はKotlin/JSの相互運用性における制限の一側面を軽減します。今後のリリースでさらなる改善が計画されています。
@JsModule
を持つファイルでの型エイリアスのサポートはデフォルトで有効になっています。
マルチプラットフォームのexpect
宣言における@JsExport
のサポート
Kotlinマルチプラットフォームプロジェクトでexpect/actual
メカニズムを使用する場合、共通コードのexpect
宣言に@JsExport
アノテーションを使用することはできませんでした。
このリリースから、expect
宣言に直接@JsExport
を適用できます。
// commonMain
// 以前はエラーになりましたが、現在は正しく動作します
@JsExport
expect class WindowManager {
fun close()
}
@JsExport
fun acceptWindowManager(manager: WindowManager) {
...
}
// jsMain
@JsExport
actual class WindowManager {
fun close() {
window.close()
}
}
JavaScriptソースセット内の対応するactual
実装にも@JsExport
でアノテーションを付ける必要があり、エクスポート可能な型のみを使用する必要があります。
この修正により、commonMain
で定義された共有コードをJavaScriptに正しくエクスポートできます。これにより、手動の回避策を使用することなく、マルチプラットフォームコードをJavaScriptのコンシューマに公開できるようになりました。
この変更はデフォルトで有効になっています。
Promise<Unit>
型での@JsExport
の使用
以前は、@JsExport
アノテーションを付けてPromise<Unit>
型を返す関数をエクスポートしようとすると、Kotlinコンパイラがエラーを生成しました。
Promise<Int>
のような戻り値の型は正しく動作しましたが、Promise<Unit>
を使用すると、「エクスポート不可能な型」の警告がトリガーされました。TypeScriptではPromise<void>
に正しくマッピングされていたにもかかわらず、です。
この制限は解除されました。現在、以下のコードはエラーなしでコンパイルされます。
// 以前は正しく動作しました
@JsExport
fun fooInt(): Promise<Int> = GlobalScope.promise {
delay(100)
return@promise 42
}
// 以前はエラーになりましたが、現在は正しく動作します
@JsExport
fun fooUnit(): Promise<Unit> = GlobalScope.promise {
delay(100)
}
この変更はKotlin/JS相互運用モデルにおける不要な制限を削除します。この修正はデフォルトで有効になっています。
Gradle
Kotlin 2.2.0はGradle 7.6.3から8.14まで完全に互換性があります。最新のGradleリリースまでのGradleバージョンも使用できます。ただし、そうすると非推奨の警告が発生したり、一部の新しいGradle機能が動作しない可能性があることに注意してください。
このリリースでは、Kotlin Gradleプラグインの診断機能にいくつかの改善が加えられています。また、バイナリ互換性検証の実験的な統合が導入され、ライブラリでの作業が容易になります。
Kotlin Gradleプラグインにバイナリ互換性検証が含まれるようになりました
ライブラリバージョン間のバイナリ互換性をチェックしやすくするために、バイナリ互換性バリデータの機能をKotlin Gradleプラグイン(KGP)に移行する実験を行っています。おもちゃのプロジェクトで試すことはできますが、まだ本番環境での使用は推奨しません。
元のバイナリ互換性バリデータは、この実験段階中も引き続きメンテナンスされます。
Kotlinライブラリは2つのバイナリフォーマットのいずれかを使用できます: JVMクラスファイルまたはklib
。これらのフォーマットは互換性がないため、KGPはそれぞれを個別に処理します。
バイナリ互換性検証機能を有効にするには、build.gradle.kts
ファイルのkotlin{}
ブロックに以下を追加します。
// build.gradle.kts
kotlin {
@OptIn(org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation::class)
abiValidation {
// 古いGradleバージョンとの互換性を確保するためにset()関数を使用します
enabled.set(true)
}
}
プロジェクトにバイナリ互換性をチェックしたい複数のモジュールがある場合、各モジュールで個別に機能を設定します。各モジュールは独自のカスタム設定を持つことができます。
有効にしたら、checkLegacyAbi
Gradleタスクを実行して、バイナリ互換性の問題をチェックします。タスクはIntelliJ IDEAまたはプロジェクトディレクトリのコマンドラインから実行できます。
./gradlew checkLegacyAbi
このタスクは、現在のコードからアプリケーションバイナリインターフェース(ABI)ダンプをUTF-8テキストファイルとして生成します。タスクは、新しいダンプを以前のリリースからのものと比較します。違いが見つかった場合、それらをエラーとして報告します。エラーを確認し、変更が許容できると判断した場合は、updateLegacyAbi
Gradleタスクを実行して参照ABIダンプを更新できます。
クラスのフィルタリング
この機能により、ABIダンプ内のクラスをフィルタリングできます。名前または部分名で明示的にクラスを含めたり除外したり、またはそれらをマークするアノテーション(またはアノテーション名の一部)によってフィルタリングできます。
例えば、このサンプルはcom.company
パッケージ内のすべてのクラスを除外します。
// build.gradle.kts
kotlin {
@OptIn(org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation::class)
abiValidation {
filters.excluded.byNames.add("com.company.**")
}
}
バイナリ互換性バリデータの設定について詳しくは、KGP APIリファレンスを参照してください。
マルチプラットフォームの制限
マルチプラットフォームプロジェクトで、ホストがすべてのターゲットのクロスコンパイルをサポートしていない場合、KGPは、他のターゲットからのABIダンプをチェックすることで、サポートされていないターゲットのABI変更を推論しようとします。このアプローチは、後ですべてのターゲットをコンパイルできるホストに切り替えた場合に、誤った検証失敗を回避するのに役立ちます。
KGPがサポートされていないターゲットのABI変更を推論しないように、このデフォルトの動作を変更するには、build.gradle.kts
ファイルに以下を追加します。
// build.gradle.kts
kotlin {
@OptIn(org.jetbrains.kotlin.gradle.dsl.abi.ExperimentalAbiValidation::class)
abiValidation {
klib {
keepUnsupportedTargets = false
}
}
}
ただし、プロジェクトにサポートされていないターゲットがある場合、タスクがABIダンプを作成できないため、checkLegacyAbi
タスクの実行は失敗します。この動作は、他のターゲットから推論されたABI変更による互換性のない変更を見逃すよりも、チェックが失敗する方が重要である場合に望ましいです。
Kotlin Gradleプラグインのコンソールにおけるリッチ出力のサポート
Kotlin 2.2.0では、Gradleビルドプロセス中に、コンソールでの色やその他のリッチ出力をサポートします。これにより、報告される診断情報をより読みやすく、理解しやすくします。
リッチ出力はLinuxおよびmacOSのサポートされているターミナルエミュレーターで利用可能であり、Windowsのサポート追加に取り組んでいます。
この機能はデフォルトで有効ですが、上書きしたい場合、gradle.properties
ファイルに以下のGradleプロパティを追加してください。
org.gradle.console=plain
このプロパティとそのオプションの詳細については、Gradleのログ形式のカスタマイズに関するドキュメントを参照してください。
KGP診断におけるProblems APIの統合
以前は、Kotlin Gradleプラグイン(KGP)は、警告やエラーなどの診断情報を、コンソールやログにプレーンテキスト出力としてしか報告できませんでした。
2.2.0以降、KGPは追加のレポートメカニズムを導入します: 現在はGradleのProblems APIを使用しています。これは、ビルドプロセス中にリッチで構造化された問題情報を報告する標準化された方法です。
KGP診断は、Gradle CLIやIntelliJ IDEAなど、異なるインターフェースでより読みやすく、より一貫して表示されるようになりました。
この統合は、Gradle 8.6以降からデフォルトで有効になっています。 APIはまだ進化中であるため、最新の改善を活用するために最新のGradleバージョンを使用してください。
KGPと--warning-mode
の互換性
Kotlin Gradleプラグイン(KGP)診断は、固定された重要度レベルで問題を報告していました。これは、Gradleの--warning-mode
コマンドラインオプションがKGPのエラー表示方法に影響を与えなかったことを意味します。
現在、KGP診断は--warning-mode
オプションと互換性があり、より柔軟性を提供します。例えば、すべての警告をエラーに変換したり、警告を完全に無効にしたりできます。
この変更により、KGP診断は選択された警告モードに基づいて出力を調整します。
--warning-mode=fail
を設定すると、Severity.Warning
の診断はSeverity.Error
に昇格されます。--warning-mode=none
を設定すると、Severity.Warning
の診断はログに記録されません。
この動作は2.2.0からデフォルトで有効になっています。
--warning-mode
オプションを無視するには、gradle.properties
ファイルに以下のGradleプロパティを設定してください。
kotlin.internal.diagnostics.ignoreWarningMode=true
新しい実験的なビルドツールAPI
Gradle、Maven、AmperなどのさまざまなビルドシステムでKotlinを使用できます。ただし、インクリメンタルコンパイル、Kotlinコンパイラプラグイン、デーモン、Kotlin Multiplatformとの互換性など、完全な機能セットをサポートするために各システムにKotlinを統合することは、多大な労力を必要とします。
このプロセスを簡素化するために、Kotlin 2.2.0は新しい実験的なビルドツールAPI(BTA)を導入します。BTAは、ビルドシステムとKotlinコンパイラエコシステム間の抽象化レイヤーとして機能する普遍的なAPIです。このアプローチにより、各ビルドシステムは単一のBTAエントリーポイントをサポートするだけでよくなります。
現在、BTAはKotlin/JVMのみをサポートしています。JetBrainsのKotlinチームは、Kotlin Gradleプラグイン(KGP)とkotlin-maven-plugin
で既にこれを使用しています。これらのプラグインを通じてBTAを試すことはできますが、API自体は、独自のビルドツール統合での一般的な使用にはまだ準備ができていません。BTAの提案に興味がある場合、またはフィードバックを共有したい場合、このKEEP提案を参照してください。
BTAを試すには:
- KGPの場合、
gradle.properties
ファイルに以下のプロパティを追加してください。
kotlin.compiler.runViaBuildToolsApi=true
- Mavenの場合、何もする必要はありません。デフォルトで有効になっています。
BTAは現在、Mavenプラグインに直接的なメリットはありませんが、Kotlinデーモンのサポートやインクリメンタルコンパイルの安定化など、新機能のより迅速な提供のための確固たる基盤を築きます。
KGPの場合、BTAを使用することですでに以下のメリットがあります。
「インプロセス」コンパイラ実行戦略の改善
KGPは3つのKotlinコンパイラ実行戦略をサポートしています。Gradleデーモンプロセス内でコンパイラを実行する「インプロセス」戦略は、以前はインクリメンタルコンパイルをサポートしていませんでした。
現在、BTAを使用することで、「インプロセス」戦略はインクリメンタルコンパイルをサポートするようになりました。使用するには、gradle.properties
ファイルに以下のプロパティを追加してください。
kotlin.compiler.execution.strategy=in-process
Kotlinからの異なるコンパイラバージョン設定の柔軟性
ビルドスクリプトの非推奨を処理しながら新しい言語機能を試すなど、コードで新しいKotlinコンパイラバージョンを使用しながら、KGPを古いバージョンのままにしたい場合があります。または、KGPのバージョンを更新し、古いKotlinコンパイラバージョンを保持したい場合もあります。
BTAはこれを可能にします。build.gradle.kts
ファイルで次のように設定できます。
// build.gradle.kts
import org.jetbrains.kotlin.buildtools.api.ExperimentalBuildToolsApi
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
plugins {
kotlin("jvm") version "2.2.0"
}
group = "org.jetbrains.example"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
kotlin {
jvmToolchain(8)
@OptIn(ExperimentalBuildToolsApi::class, ExperimentalKotlinGradlePluginApi::class)
compilerVersion.set("2.1.21") // 2.2.0とは異なるバージョン
}
BTAは、KGPとKotlinコンパイラバージョンを、過去3つのメジャーバージョンと将来の1つのメジャーバージョンで設定することをサポートします。したがって、KGP 2.2.0では、Kotlinコンパイラバージョン2.1.x、2.0.x、および1.9.25がサポートされます。KGP 2.2.0は、将来のKotlinコンパイラバージョン2.2.xおよび2.3.xとも互換性があります。
ただし、異なるコンパイラバージョンをコンパイラプラグインと組み合わせて使用すると、Kotlinコンパイラ例外が発生する可能性があることに注意してください。Kotlinチームは、今後のリリースでこれらの問題に対処する予定です。
これらのプラグインでBTAを試して、KGPとMavenプラグイン専用のYouTrackチケットでフィードバックをお寄せください。
Kotlin標準ライブラリ
Kotlin 2.2.0では、Base64
APIとHexFormat
APIが安定版になりました。
Base64エンコーディングとデコーディングの安定化
Kotlin 1.8.20はBase64エンコーディングとデコーディングの実験的なサポートを導入しました。 Kotlin 2.2.0では、Base64 APIは現在安定版であり、4つのエンコーディングスキームが含まれ、このリリースで新しいBase64.Pem
が追加されました。
Base64.Default
は、標準のBase64エンコーディングスキームを使用します。Base64.Default
はBase64
クラスのコンパニオンオブジェクトです。 結果として、Base64.Default.encode()
やBase64.Default.decode()
の代わりに、Base64.encode()
やBase64.decode()
でその関数を呼び出すことができます。Base64.UrlSafe
は、"URLおよびファイル名セーフ"エンコーディングスキームを使用します。Base64.Mime
は、MIMEエンコーディングスキームを使用し、エンコード中に76文字ごとに改行文字を挿入し、デコード中に不正な文字をスキップします。Base64.Pem
はBase64.Mime
のようにデータをエンコードしますが、行の長さを64文字に制限します。
Base64 APIを使用して、バイナリデータをBase64文字列にエンコードし、バイトにデコードするために使用できます。
以下に例を示します。
val foBytes = "fo".map { it.code.toByte() }.toByteArray()
Base64.Default.encode(foBytes) // "Zm8="
// Alternatively:
// Base64.encode(foBytes)
val foobarBytes = "foobar".map { it.code.toByte() }.toByteArray()
Base64.Url