Kotlin 2.4 新特性详解:多端互操作性再进化与标准库提效

Kotlin · 版本发布 2.4

Kotlin 2.4 新特性详解:多端互操作性再进化与标准库提效

kotlinKotlin版本发布2.4.20编程语言

数据源:GitHub Releases + 官方博客 + HN

Kotlin 官方于 2026 年 9 月 7 日正式发布 2.4.20 版本。本次更新将 JVM 平台上 when 表达式的 invokedynamic 编译优化转为稳定版,并为标准库、Native 和 Wasm 带来大量升级。下面按主题逐一展开。

when 表达式的 invokedynamic 编译支持(稳定版)

早在 Kotlin 2.2.20 中,官方就引入了在 JVM 21 及更高版本上使用 invokedynamic 编译 when 表达式的实验性支持。经过多个版本的打磨,在 Kotlin 2.4.20 中,该特性终于毕业为稳定版(Stable),并且在默认情况下自动开启。这一改进能够有效减少字节码大小并提升模式匹配的执行效率。

检查集合元素相等性与唯一性的新函数

在过去的 Kotlin 版本中,如果想要检查集合中的所有元素是否全部相同或者全部唯一,开发者通常需要手动编写较为低效的代码模式。为了填补这一空白,Kotlin 2.4.20 在标准库中引入了四个实验性的新函数:allDistinct()、allDistinctBy()、allEqual() 和 allEqualBy()。

它们和现有集合操作一样使用结构相等性比较元素,支持集合、序列和数组。此为实验性特性,需标注 @OptIn(ExperimentalStdlibApi::class)。

官方示例代码:

@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
}

kotlin.test 断言函数的新重载

Kotlin 2.4.20 为 kotlin.test 包下常见的断言函数(如 assertTrue()、assertEquals()、assertSame()、assertContains() 等)添加了全新的函数重载。

以前,断言函数只接受预格式化的字符串错误消息,即使断言成功也会构建字符串。新版重载接受一个 lambda,仅在断言失败时进行惰性求值生成错误信息。

这使 API 风格与 JUnit 5 保持一致并大幅提升性能,特别利好生成详细错误消息的 Power-assert 插件项目。

官方示例代码:

import kotlin.test.ExperimentalKotlinTestApi
import kotlin.test.assertEquals
import kotlin.test.assertTrue

@OptIn(ExperimentalKotlinTestApi::class)
fun testValues(actual: Int, expected: Int, items: List<String>) {
    // 错误消息只会在断言失败时被构建
    assertTrue(actual > 0) { "Expected a positive value but got $actual" }

    // 避免对列表进行无用的格式化,除非断言失败
    assertEquals(expected, actual) { "Unexpected value for items: ${items.joinToString()}" }
}

支持协程堆栈跟踪恢复

Kotlin 2.4.20 在标准库中新增了 StackTraceRecoverable 接口。这是一个非常实用的实验性底层改进,极大地增强了语言与 kotlinx.coroutines 库的集成度。

协程调试时,常遇到异常被另一协程重新抛出的情况,堆栈跟踪恢复可帮助看清异常来源。若自定义异常类有额外必需参数(如行号),直接实现 StackTraceRecoverable 接口并重写 copyForStackTraceRecovery() 方法即可。这样无需显式依赖 kotlinx.coroutines,便能定义创建新异常实例的规则。

官方示例代码:

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

@OptIn(ExperimentalStdlibCoroutineSupportApi::class)
class FileEditException
private constructor(
    val line: Int,
    private val detail: String,
    cause: Throwable?,
) : IllegalStateException("When editing line $line: $detail", cause),
    StackTraceRecoverable<FileEditException> {

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

    override fun copyForStackTraceRecovery(): FileEditException =
        FileEditException(line, detail, this)
}

新的 Swift 导出特性

Kotlin/Native 在此版本中继续深耕互操作性,为 Swift 导出带来了两项关键功能:

  1. 密封类(Sealed classes)支持:现在在 Kotlin 中定义的密封类层次结构将被原生映射为 Swift 的枚举(enum)。这使得 Swift 开发者可以在 Xcode 中直接使用具有完整自动补全的、穷尽的 switch 语句,而不需要再硬编码 default 分支。
  2. 跨语言继承(Cross-language inheritance):支持了在 Kotlin 中定义接口和基础类,并在 Swift 侧使用纯 Swift 库来实现它们,最后再把 Swift 对象回传给 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 侧
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"

Kotlin/Wasm 新的编译模式

以往 Kotlin/Wasm 编译器只支持单体编译模式(monolith),将整个项目和依赖打包到一起以实现最大程度的死代码消除和极小的产物体积。Kotlin 2.4.20 为 Kotlin/Wasm 新增了多模块编译模式,开发者现在可以在 gradle.properties 中选择:

  • monolith(默认):整体编译,移除不可达声明,对整个程序应用优化。
  • multimodule-open-world:独立编译各模块,模块间无跨模块优化,会产生单独的二进制文件,适合加快开发编译速度。
  • multimodule-closed-world:一次调用处理所有模块,移除不可达声明并单独优化每个 Wasm 二进制文件。

在开发中,建议采用 kotlin.wasm.compilationMode=multimodule-closed-world-only-in-dev,借此缩短开发阶段的重新编译耗时,同时保障生产构建体积最小。

破坏性变更与注意事项

在升级到 Kotlin 2.4.20 之前,请务必关注以下破坏性变更和过时特性的弃用情况。

  • Apple watchOS 32 位平台已弃用:由于苹果已放弃对 32 位 watchOS 的支持,watchosArm32 这一 Kotlin/Native 目标也被正式弃用,并计划在未来的 Kotlin 2.5.0 中彻底移除。
  • 内联函数中限制 AtomicFU:在 public inline 函数或跨文件调用的 internal inline 函数中,现在编译器完全禁止使用 AtomicFU 原子操作。
  • Webpack import.meta 行为变更:Kotlin 2.4.20 将 Webpack 更新到了 5.108.1 版本。新版 Webpack 不再忽略 import.meta,这会导致包含此标识的 CommonJS 兼容代码被强制按 ES 模块解析,可能引发打包错误。
  • Kotlin/Wasm wasmExports 弃用:生成的 JavaScript wasmExports API 已被标为废弃。除 wasmExports.memory 仍被允许临时使用外,编译器不再允许访问其他导出项。

升级建议

维度建议
谁应该升级所有 Kotlin 开发者,尤其是重度依赖多端平台互操作(Native、Wasm、JS 端)及希望在测试用例中提升断言性能的开发者。
何时升级推荐当前即可升级。请确保您的 IDE(IntelliJ IDEA 或 Android Studio)已更新至最新版本,随后在构建脚本中将 Kotlin 版本修改为 2.4.20 即可。
注意事项若项目依赖 watchosArm32 平台需尽早迁移;JS 和 Wasm 项目若因 Webpack 升级引发模块格式误判错误,请检查是否受到 import.meta 的影响并做相应调整。

参考来源