Skip to content
EAP

Kotlin 2.4.20-RC3 的新功能

發佈日期:September 2, 2026

本文件並未涵蓋早期體驗預覽 (EAP) 發佈版的所有功能,但重點介紹了一些重大改進。

請參閱 GitHub 變更日誌 中的完整變更列表。

Kotlin 2.4.20-RC3 版本已發佈!以下是此 EAP 版本的一些詳細資訊:

有關 Kotlin 發佈週期的資訊,請參閱 Kotlin 發佈程序

更新到 Kotlin 2.4.20-RC3

最新版本的 Kotlin 已包含在最新版本的 IntelliJ IDEAAndroid Studio 中。

若要更新到新的 Kotlin 版本,請確保您的 IDE 已更新至最新版本,並在建置指令碼中將 Kotlin 版本更改為 2.4.20-RC3。

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

此版本提供以下預覽版(pre-stable)功能。這包括具有 BetaAlpha實驗性 狀態的功能:

標準函式庫

Kotlin 2.4.20-RC3 新增了對協同程式堆疊追蹤恢復的支援,並引入了用於檢查集合元素相等性和唯一性的新函式。

Experimental

支援協同程式堆疊追蹤恢復

Kotlin 2.4.20-RC3 在標準函式庫中新增了 StackTraceRecoverable 介面。這改進了與 kotlinx.coroutines 程式庫的整合,因為它讓您可以定義如何為堆疊追蹤恢復建立新的例外執行個體,而無需增加對 kotlinx.coroutines 的相依性。

當一個協同程式拋出例外,而另一個協同程式重新拋出它時,堆疊追蹤恢復有助於偵錯。它讓您可以查看例外的源頭以及另一個協同程式在哪裡重新拋出它。

kotlinx.coroutines 程式庫透過建立一個包含額外協同程式堆疊追蹤資訊的新例外執行個體來執行堆疊追蹤恢復。對於建構函式僅接受例外訊息、原因、兩者皆有或不含參數的例外,這會自動發生。

如果例外建構函式具有額外的必要參數(例如行號或錯誤代碼),請實作 StackTraceRecoverable 介面,以定義 kotlinx.coroutines 程式庫如何建立該例外的新執行個體。

若要實作此介面,請覆寫 copyForStackTraceRecovery() 函式。此函式會回傳一個用於堆疊追蹤恢復的新例外執行個體,如果您不希望 kotlinx.coroutines 程式庫複製該例外,則回傳 null

StackTraceRecoverable 介面在所有目標上皆可用,但 kotlinx.coroutines 程式庫僅在 JVM 上將其用於堆疊追蹤恢復。

這些 API 處於實驗性階段,需要使用 @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()每個物件在選定的屬性上都具有相同的值。

您可以在集合、序列和陣列上使用這些函式。它們使用結構相等性來比較元素,就像其他集合操作一樣。

這些函式處於實驗性階段,需要使用 @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 帶來了新的 Swift 匯出功能(包括對密封類別和跨語言繼承的支援),以及為 SwiftPM 相依性自動產生的 Package.swift 檔案。

新的 Swift 匯出功能

密封類別

Kotlin 2.4.20-RC3 在 Swift 匯出中新增了對密封類別(sealed classes)和介面的支援。

先前,您必須為密封型別的每個 switch 陳述式編寫一個 default 情況。現在,在 Kotlin 中定義的密封階層結構會對應到 Swift 列舉(enums),從而在 Xcode 中實現具有完整自動補全功能的窮舉 switch 陳述式。

Swift 匯出會在每個密封型別上產生一個 .sealedType() 方法。此方法會回傳一個 Swift 列舉,其成員與密封階層的直接子類別相符。您可以巢狀呼叫這些方法來匹配更深層的階層結構。

例如,在 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 端,您可以使用窮舉 switch 而無需 default 情況:

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 匯出中的跨語言繼承

Kotlin 2.4.20-RC3 在 Swift 匯出中引入了跨語言繼承支援。

此功能的一個常見使用案例是反向匯入模式,即您在 Kotlin 中定義合約,並在 Swift 端提供平台特定的實作。 當您需要使用無法直接匯入 Kotlin 的純 Swift 程式庫時,這特別有用。

若要實作此模式,請宣告一個供 Swift 實作繼承的 Kotlin open 基底類別以及一個 Kotlin 介面。然後在 Swift 中實作該介面,並將 Swift 物件傳遞給接受該介面的 Kotlin 函式。例如,針對 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 匯出的詳細資訊,請參閱我們的文件

為 SwiftPM 相依性產生的 Package.swift

匯出相依於 SwiftPM 套件的 XCFramework 時,您必須發佈生成的 SwiftPM 套件才能正確解析。為了協助此操作,assembleSharedXCFramework Gradle 任務現在會產生一個 Package.swift 檔案,以便與 XCFramework 一起散佈。

如需詳細資訊,請參閱 SwiftPM 匯出頁面

Kotlin/Wasm

Kotlin 2.4.20-RC3 更改了 Kotlin/Wasm 處理 @JsFun 宣告中頂層 require() 呼叫的方式,使伴隨物件的初始化順序與 JVM 行為一致,並在 Kotlin Gradle 外掛程式中新增了對 Wasmtime 作為 wasmWasi 目標執行階段的支援。

針對 @JsFun 宣告中頂層 require() 呼叫的變更

@JsFun 宣告使用頂層 require() 函式時,Kotlin/Wasm 現在會報錯。

先前,編譯器會在 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() 運算式。新增 /* webpackIgnore: true */ 魔術註解以防止 webpack 解析該動態匯入:

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 引入了對 Wasmtime 作為 Kotlin Gradle 外掛程式中 wasmWasi 目標執行階段的支援。

先前,wasmWasi 目標僅支援 Node.js 執行階段,這需要 JavaScript 引導才能執行 WASI 應用程式。透過 Wasmtime 支援,您現在可以在獨立的 WebAssembly 執行階段上執行 Kotlin/Wasm 應用程式。

若要使用 Wasmtime 作為 wasmWasi 目標的執行階段,請將 wasmtime() 新增到您的 Gradle 建置檔案中:

kotlin
kotlin {
    wasmWasi {
        wasmtime()
    }
}

我們歡迎您在 YouTrack 中向我們提供回饋。

Kotlin/JS

Kotlin 2.4.20-RC3 引入了一種新的實驗性 DSL 用於瀏覽器測試,並新增了支援將 suspend lambda 匯出為 JavaScript async 函式的功能。

Experimental

用於瀏覽器測試的新 DSL

Kotlin 2.4.20-RC3 引入了一種新的實驗性 DSL,用於在瀏覽器環境中執行 Kotlin/JS 測試。

目前,Kotlin Gradle 外掛程式使用 Karma 作為瀏覽器啟動器,以便在不同的瀏覽器中執行 JavaScript 測試。Karma 專案已經過時 2 年了,這促使我們探索支援瀏覽器測試的替代方案。

新的 DSL 旨在取代 Karma 作為底層不同工具的管理員,其內容包括:

  • Mocha 作為測試執行器。
  • Webpack 作為綑綁器(在未來版本中將被 Vite 取代)。
  • Playwright 作為瀏覽器驅動程式和發行管理員,支援 Chromium、Firefox 和 WebKit (Safari) 瀏覽器引擎。

若要嘗試新的測試 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 mode)
                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 lambda 匯出為 async 函式

在 Kotlin 2.4.20-RC3 中,您現在可以將 suspend Lambda 運算式匯出為 JavaScript async 函式。

先前,無法從 Kotlin/JS 程式庫中匯出包含 suspend lambda 的宣告。現在 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 lambda 會顯示為一般的 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 邁出了 BTA 穩定化的下一步,新增了對新目標的支援:Kotlin/JS、Kotlin/Wasm 以及 Kotlin 元資料。

這使得 Kotlin Gradle 外掛程式與編譯器的互動更加一致。在某些情況下,您還可以受益於更快、更穩定的編譯。

BTA 是一個通用 API,充當建置系統與 Kotlin 編譯器生態系統之間的抽象層。它有助於在現有的建置工具中支援 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)的第一個實驗性版本。原生映像提供了標準 kotlinc 命令列工具的直接替代方案,同時提供更快的啟動時間和更高的效能。

若要嘗試原生映像,請從 GitHub Releases 下載組建。

原生映像還捆綁了以下編譯器外掛程式,您可以透過 -Xplugin-Xcompiler-plugin CLI 選項使用它們:

如需更多關於 Kotlin 編譯器原生映像的資訊,請參閱其 README