Skip to content
EAP

Kotlin 2.4.20-RC3 の新機能

リリース日: September 2, 2026

このドキュメントは Early Access Preview (EAP) リリースのすべての機能を網羅しているわけではありませんが、主要な改善点について詳しく説明します。

変更点の完全なリストについては、GitHub の変更履歴を参照してください。

Kotlin 2.4.20-RC3 がリリースされました!この EAP リリースの主な内容は以下の通りです。

Kotlin のリリースサイクルに関する情報は、Kotlin のリリースプロセスを参照してください。

Kotlin 2.4.20-RC3 へのアップデート

最新バージョンの Kotlin は、最新バージョンの IntelliJ IDEA および Android Studio に含まれています。

新しい Kotlin バージョンにアップデートするには、IDE が最新バージョンに更新されていることを確認し、ビルドスクリプト内の Kotlin バージョンを 2.4.20-RC3 に変更してください。

新機能 {id=new-experimental-features}

このリリースでは、以下のプレステーブル(pre-stable)機能が利用可能です。これには、BetaAlpha、および 実験的 (Experimental) ステータスの機能が含まれます。

標準ライブラリ

Kotlin 2.4.20-RC3 では、コルーチンのスタックトレース復元のサポートが追加され、コレクション要素の等価性と一意性をチェックするための新しい関数が導入されました。

Experimental

コルーチンのスタックトレース復元のサポート

Kotlin 2.4.20-RC3 では、標準ライブラリに StackTraceRecoverable インターフェースが追加されました。これにより、kotlinx.coroutines への依存関係を追加することなく、スタックトレース復元のための新しい例外インスタンスの作成方法を定義できるようになり、kotlinx.coroutines ライブラリとの統合が改善されます。

スタックトレース復元は、あるコルーチンが例外をスローし、別のコルーチンがそれを再スロー(rethrow)する場合のデバッグに役立ちます。これにより、例外がどこで発生し、どのコルーチンがそれを再スローしたかを確認できるようになります。

kotlinx.coroutines ライブラリは、追加のコルーチンスタックトレース情報を含む新しい例外インスタンスを作成することで、スタックトレース復元を実行します。これは、例外メッセージのみ、原因(cause)のみ、その両方、または引数なしのコンストラクタを持つ例外に対して自動的に行われます。

例外のコンストラクタに行番号やエラーコードなどの追加の必須引数がある場合は、StackTraceRecoverable インターフェースを実装して、kotlinx.coroutines ライブラリがその例外の新しいインスタンスをどのように作成するかを定義します。

そのためには、copyForStackTraceRecovery() 関数をオーバーライドします。この関数はスタックトレース復元のための新しい例外インスタンスを返します。kotlinx.coroutines ライブラリに例外をコピーさせたくない場合は null を返します。

StackTraceRecoverable インターフェースはすべてのターゲットで使用可能ですが、kotlinx.coroutines ライブラリがスタックトレース復元のためにこれを使用するのは JVM 上のみです。

これらの API は 実験的 (Experimental) であり、@OptIn(ExperimentalStdlibCoroutineSupportApi::class) アノテーションによるオプトインが必要です。

以下は、スタックトレース復元用の新しいインスタンスを作成する際に line プロパティを保持するカスタム例外の例です。

kotlin
import kotlin.coroutines.ExperimentalStdlibCoroutineSupportApi
import kotlin.coroutines.debug.StackTraceRecoverable

@OptIn(ExperimentalStdlibCoroutineSupportApi::class)
class FileEditException
// cause を IllegalStateException コンストラクタに渡すために
// 実装にはプライベートコンストラクタが必要です
private constructor(
    val line: Int,
    private val detail: String,
    cause: Throwable?,
) : IllegalStateException("When editing line $line: $detail", cause),
    // スタックトレース復元の目的で StackTraceRecoverable を実装します
    StackTraceRecoverable<FileEditException> {

    constructor(line: Int, detail: String) : this(line, detail, null)

    // 行番号とメッセージの詳細をコピーします
    override fun copyForStackTraceRecovery(): FileEditException =
        FileEditException(line, detail, this)
    }

fun main() {
    val original = FileEditException(15, "Unexpected token")
    
    // 通常、その動作をテストする場合を除き、この関数を直接呼び出す必要はありません
    // kotlinx.coroutines ライブラリがスタックトレース復元の際に自動的に呼び出します
    val copy = original.copyForStackTraceRecovery()

    println(copy.message)
    // When editing line 15: Unexpected token

    println(copy.cause == original)
    // true
}

詳細については、この機能の KEEP を参照してください。

フィードバックを YouTrack でお待ちしております。

Experimental

コレクション要素の等価性と一意性をチェックするための新関数

Kotlin 2.4.20-RC3 より前は、コレクションの要素がすべて異なるか、あるいはすべて等しいかをチェックしたい場合、非効率的なコードパターンを使用する必要がありました。

Kotlin 2.4.20-RC3 では、このギャップを埋めるための実験的な関数が導入されました。

関数チェック内容
.allDistinct()コレクション内のすべての値が一意である。
.allDistinctBy()すべてのオブジェクトが、選択されたプロパティに対して一意の値を持つ。
.allEqual()コレクション内のすべての値が同じである。
.allEqualBy()すべてのオブジェクトが、選択されたプロパティに対して同じ値を持つ。

これらの関数はコレクション、シーケンス、および配列で使用できます。他のコレクション操作と同様に、構造的な等価性(structural equality)を使用して要素を比較します。

これらの関数は 実験的 (Experimental) であり、@OptIn(ExperimentalStdlibApi::class) アノテーションまたは -opt-in=kotlin.ExperimentalStdlibApi コンパイラオプションによるオプトインが必要です。

kotlin
@OptIn(ExperimentalStdlibApi::class)
fun main() {
    data class Response(
        val participantId: String,
        val answer: String,
        val responseDate: String
    )

    val responses = listOf(
        Response("P001", "Yes", "2026-07-21"),
        Response("P002", "Maybe", "2026-07-21"),
        Response("P003", "No", "2026-07-21")
    )

    // すべての参加者が同じ回答をしたかどうかをチェックします
    println(responses.allEqualBy { it.answer })
    // false

    // 重複した参加者がいないかチェックします
    println(responses.allDistinctBy { it.participantId })
    // true

    // すべての回答が同じ日に提出されたかどうかをチェックします
    println(responses.allEqualBy { it.responseDate })
    // true

    val answers = responses.map { it.answer }

    // 回答が同一(すべて同じ)かどうかをチェックします
    println(answers.allEqual())
    // false

    // 回答がすべて異なるかどうかをチェックします
    println(answers.allDistinct())
    // true
}

これらの関数を使用した感想などのフィードバックを YouTrack でお待ちしております。

Kotlin/Native

Kotlin 2.4.20-RC3 では、シールドクラスのサポートや言語を跨いだ継承(cross-language inheritance)を含む新しい Swift export 機能が導入され、SwiftPM 依存関係用の Package.swift ファイルが自動生成されるようになりました。

新しい Swift export 機能

シールドクラス

Kotlin 2.4.20-RC3 では、Swift export にシールドクラス(sealed classes)とインターフェースのサポートが追加されました。

以前は、シールド型に対するすべての switch 文において default ケースを記述する必要がありました。今回のアップデートにより、Kotlin で定義されたシールド階層が Swift の enum にマッピングされ、Xcode で完全な自動補完を伴う網羅的な(exhaustive) switch 文が使用可能になりました。

Swift export は、各シールド型に対して .sealedType() メソッドを生成します。このメソッドは、シールド階層の直接のサブクラスと一致するケースを持つ Swift enum を返します。これらの呼び出しを入れ子にすることで、より深い階層に一致させることもできます。

例えば、Kotlin でクラス階層を持つシールドインターフェースを宣言します。

kotlin
// Kotlin
sealed interface Shape

class Circle : Shape {
   override fun toString(): String = "Circle"
}

class Rectangle : Shape {
   override fun toString(): String = "Rectangle"
}

fun createCircle(): Shape = Circle()

Swift 側では、default ケースなしで網羅的な switch を使用できます。

swift
// Swift
let shape = createCircle()

let name = switch shape.sealedType() {
   case let .circle(type): "It's a \(type.value)"
   case let .rectangle(type): "It's a \(type.value)"
}
// name == "It's a Circle"

switch が網羅的であるため、シールド階層に新しいサブクラスが追加されるとコンパイラが警告を出します。これにより、default ケースに頼るのではなく、すぐに対応することが可能になります。

Swift export における言語を跨いだ継承

Kotlin 2.4.20-RC3 では、Swift export に言語を跨いだ継承(cross-language inheritance)のサポートが導入されました。

この機能の一般的なユースケースは、リバースインポート パターンです。これは、Kotlin でコントラクト(規約)を定義し、Swift 側でプラットフォーム固有の実装を提供する場合です。 これは、Kotlin に直接インポートできない純粋な Swift ライブラリを使用する必要がある場合に特に便利です。

このパターンを実装するには、Swift の実装が継承するための Kotlin スーパークラスと、Kotlin インターフェースを宣言します。次に、そのインターフェースを Swift で実装し、そのインターフェースを受け入れる Kotlin 関数に Swift オブジェクトを渡します。例えば、CryptoKit ライブラリの場合:

  1. Kotlin 側で、open なベースクラスと、それを受け入れる関数を持つ Kotlin インターフェースを宣言します。

    kotlin
    // Kotlin
    interface CryptoProvider {
       fun hashMD5(input: String): String
    }
    
    fun processHash(provider: CryptoProvider, input: String): String = provider.hashMD5(input)
    
    open class SwiftBase
  2. Swift 側で、エクスポートされた SwiftBase クラスを継承し、純粋な Swift ライブラリを使用してインターフェースを実装し、そのオブジェクトを Kotlin に渡します。

    swift
    // Swift
    import CryptoKit
    
    final class IosCryptoProvider: SwiftBase, CryptoProvider {
       func hashMD5(input: String) -> String {
           guard let data = input.data(using: .utf8) else { return "failed" }
           return Insecure.MD5.hash(data: data).description
       }
    }
    
    let provider = IosCryptoProvider()
    
    // 呼び出しは Swift の実装にディスパッチされます
    print(processHash(provider: provider, input: "Hello, world!"))

Kotlin が Swift オブジェクトを受け取ると、それを通常のインターフェースの実装として扱い、Swift コードを実行します。

Swift export の詳細については、ドキュメント を参照してください。

SwiftPM 依存関係用の Package.swift の生成

SwiftPM パッケージに依存する XCFramework をエクスポートする場合、正しく解決されるように、結果として得られる SwiftPM パッケージを公開する必要があります。これを支援するため、assembleSharedXCFramework Gradle タスクは、XCFramework と共に配布される Package.swift ファイルを生成するようになりました。

詳細は、SwiftPM export のページ を参照してください。

Kotlin/Wasm

Kotlin 2.4.20-RC3 では、@JsFun 宣言におけるトップレベルの require() 呼び出しの処理方法が変更され、コンパニオンオブジェクトの初期化順序が JVM の動作に合わせられました。また、Kotlin Gradle プラグインにおいて wasmWasi ターゲットのランタイムとして Wasmtime がサポートされました。

@JsFun 宣言におけるトップレベルの require() 呼び出しの変更

Kotlin/Wasm は、@JsFun 宣言がトップレベルの require() 関数を使用している場合にエラーを報告するようになりました。

以前、コンパイラは import-object.mjs ファイル内に require 変数を生成しており、@JsFun 宣言から require() を呼び出すことが可能でした。

この動作は意図せずコンパイラの実装詳細を公開してしまっていました。この動作からの移行をサポートするため、Kotlin/Wasm はこの生成された require 宣言を削除し、コンパイラはこのような呼び出しに対してエラーを報告するようになりました。例:

kotlin
// エラーを報告します
@JsFun("(mod) => require(mod)")
external fun loadModule(mod: String): JsAny

この変更に備えて、@JsFun 宣言内のトップレベルの require() 呼び出しを @JsModule アノテーションに置き換えてください。

kotlin
@JsModule("module")
external val module: Module

external interface Module {
    // 期待されるモジュールメンバーを定義します
}

動的なモジュール読み込みには、代わりに import() 式を使用してください。webpack が動的インポートを解析するのを防ぐために、/* webpackIgnore: true */ マジックコメントを追加してください。

kotlin
@JsFun("""
    ((module) => () => module)(
        await import(/* webpackIgnore: true */ "module")
    )
""")
private external fun loadModuleDynamically(): JsAny?

また、import() 式を条件付きで使用することもできます。例えば、Node.js で実行されている場合にのみモジュールを読み込むことができます。

kotlin
@JsFun("""
    ((module) => () => module)(
        ((typeof process !== "undefined") && (process.release.name === "node"))
            ? await import(/* webpackIgnore: true */ "module")
            : null
    )
""")
private external fun loadNodeModule(): JsAny?

プロジェクトがトップレベルの require() 関数を必要とする依存関係に依存している場合は、ワークアラウンドとして globalThis のプロパティに追加してください。

kotlin
@JsFun("""
    ((module) => {
        globalThis.require = module.default.createRequire(import.meta.url)
        return () => {}
    })(await import("node:module"))
""")
external fun defineRequire()

問題が発生した場合は、イシュートラッカー でフィードバックを共有してください。

コンパニオンオブジェクトの初期化順序の改善

Kotlin/Wasm は、JVM の動作に合わせて、サブクラスのコンパニオンオブジェクトよりも先にスーパークラスのコンパニオンオブジェクトを初期化するようになりました。以前は、初期化が逆になる可能性があり、プラットフォーム間で動作が一致していませんでした。

このアップデートにより、クロスプラットフォームの一貫性が向上し、クラス初期化の動作におけるプラットフォーム固有の違いが減少します。また、中間クラスがコンパニオンオブジェクトを宣言していないケースを含む、より深い継承階層におけるコンパニオンオブジェクトの初期化を正しく処理できるようになります。

Kotlin Gradle プラグインにおける Wasmtime のサポート

Kotlin 2.4.20-RC3 では、Kotlin Gradle プラグインにおいて wasmWasi ターゲットのランタイムとして Wasmtime のサポートが導入されました。

以前は、wasmWasi ターゲットは Node.js ランタイムのみをサポートしており、WASI アプリケーションを実行するには JavaScript のブートストラップが必要でした。Wasmtime のサポートにより、Kotlin/Wasm アプリケーションをスタンドアロンの WebAssembly ランタイムで実行できるようになりました。

wasmWasi ターゲットのランタイムとして Wasmtime を使用するには、Gradle ビルドファイルに wasmtime() を追加してください。

kotlin
kotlin {
    wasmWasi {
        wasmtime()
    }
}

フィードバックを YouTrack でお待ちしております。

Kotlin/JS

Kotlin 2.4.20-RC3 では、ブラウザテスト用の新しい実験的な DSL が導入され、suspend ラムダを JavaScript の async 関数としてエクスポートする機能のサポートが追加されました。

Experimental

ブラウザテスト用の新しい DSL

Kotlin 2.4.20-RC3 では、ブラウザ環境で Kotlin/JS テストを実行するための新しい実験的な DSL が導入されました。

現在、Kotlin Gradle プラグインは、異なるブラウザ間で JavaScript テストを実行するためのブラウザランチャーとして Karma を使用しています。Karma プロジェクトは 2 年前から非推奨となっており、ブラウザテストをサポートするための代替手段を模索してきました。

新しい DSL は、内部でさまざまなツールを管理するマネージャーとして Karma を置き換えることを目的としており、以下のものが含まれています。

  • テストランナーとしての Mocha
  • バンドラーとしての Webpack将来のリリースVite に置き換えられる予定です)。
  • ブラウザドライバーおよび Chromium、Firefox、WebKit (Safari) ブラウザエンジンの配布マネージャーとしての Playwright

新しいテスト用 DSL を試すには、Kotlin/JS ターゲット内の browser{} ブロックにオプトインの test{} ブロックを追加してください。

kotlin
import org.jetbrains.kotlin.gradle.ExperimentalJsTestDsl
import kotlin.time.Duration.Companion.seconds

kotlin {
    js {
        browser {
            @OptIn(ExperimentalJsTestDsl::class)
            // 新しい test{} ブロックを追加し構成します
            test {
                // すべてのランナーに共通のタイムアウトを設定します
                timeout = 2.seconds
                // Gradle プロバイダーを使用してヘッドレスモードを構成します
                headless = providers
                    .environmentVariable("IS_IN_CI")
                    .map { it.toBoolean() }
                    .orElse(false)
                // Chromium テストランナーを有効にし構成します
                chromium {
                    // 共通のタイムアウトオプションをオーバーライドします
                    timeout = 5.seconds
                    // 追加の起動引数を追加します
                    launchArgs.add("--no-sandbox")
                }
                // Firefox テストランナーを有効にします
                firefox()
                // WebKit テストランナーを有効にします
                webkit()
                // 追加の WebKit テストランナーを有効にし構成します
                webkit("noheadless") {
                    // カスタムオプションを設定します
                    headless = false
                }
            }
        }
    }
}

新しい DSL は活発に開発中です。フィードバックを YouTrack でお待ちしております。

suspend ラムダを async 関数としてエクスポートする機能のサポート

Kotlin 2.4.20-RC3 では、suspend ラムダ式 を JavaScript の async 関数としてエクスポートできるようになりました。

以前は、suspend ラムダを含む宣言を Kotlin/JS ライブラリからエクスポートする方法がありませんでした。今回のアップデートにより、Kotlin コンパイラは Kotlin の suspend 関数とネイティブ JavaScript の async/await モデルの間のブリッジ(連携)を自動的に処理するようになり、Kotlin と TypeScript が混在するコードベースで便利に使用できます。

この機能を有効にするには、build.gradle.kts ファイルに以下のコンパイラオプションを追加してください。

kotlin
kotlin {
    js {
        compilations.all {
            compileTaskProvider.configure {
                compilerOptions {
                    freeCompilerArgs.add("-Xsuspend-lambda-exporting")
                }
            }
        }
    }
}

次に、関連する宣言に @JsExport を付与します。

kotlin
// Kotlin
@JsExport
class TaskRunner {
    suspend fun runTask(task: suspend () -> String): String {
        return task()
    }
}

TypeScript 側からは、suspend ラムダは通常の async 関数として見えます。

typescript
// TypeScript
import { TaskRunner } from "..."

const runner = new TaskRunner();
const result = await runner.runTask(async () => "done");
console.log(result); // "done"

@JsExport アノテーションの詳細については、ドキュメント を参照してください。

ビルドツール API

Experimental

Kotlin/JS、Kotlin/Wasm、および Kotlin メタデータのサポート

Kotlin 2.2.0 では、ビルドツール API (BTA) が Kotlin/JVM で利用可能になりました。Kotlin 2.4.20-RC3 では、新しいターゲット(Kotlin/JS、Kotlin/Wasm、および Kotlin メタデータ)のサポートを追加することで、BTA の安定化に向けた次のステップに進みます。

これにより、Kotlin Gradle プラグインとコンパイラの相互作用がより一貫したものになります。また、一部のケースでは、より高速で安定したコンパイルの恩恵を受けることができます。

BTA は、ビルドシステムと Kotlin コンパイラエコシステムの間の抽象化レイヤーとして機能するユニバーサルな API です。これは、利用可能なビルドツールにおいて、Kotlin の機能のサポートと Kotlin コンパイラとの互換性を確保するのに役立ちます。

Kotlin 2.4.20-RC3 では、新しいターゲットでの BTA はオプトインとして利用可能になります。試すには、gradle.properties ファイルに対応するプロパティを追加してください。

properties
kotlin.wasm.runViaBuildToolsApi=true
kotlin.js.runViaBuildToolsApi=true
kotlin.metadata.runViaBuildToolsApi=true

Kotlin 2.5.0 以降、Kotlin/JS、Kotlin/Wasm、および Kotlin メタデータで BTA をデフォルトで有効にする予定です。

BTA の提案について詳しく知りたい、またはフィードバックを共有したい場合は、この KEEP を参照してください。

Experimental

Kotlin コンパイラ: ネイティブイメージ

Kotlin 2.4.20-RC3 では、Kotlin コンパイラネイティブイメージ(native image)の最初の 実験的 (Experimental) リリースが行われました。ネイティブイメージは、標準の kotlinc コマンドラインツールをそのまま置き換え可能な(drop-in replacement)ものとして提供され、起動時間の短縮と高いパフォーマンスを実現します。

ネイティブイメージを試すには、GitHub Releases からビルドをダウンロードしてください。

ネイティブイメージには、CLI オプションの -Xplugin または -Xcompiler-plugin で使用できる以下のコンパイラプラグインも同梱されています。

Kotlin コンパイラネイティブイメージの詳細については、その README を参照してください。