4.2 Kotlin 2.4.0 新特性
25 分钟阅读
4.2 Kotlin 2.4.0 新特性
阅读 Kotlin 2.4.0 版本说明,了解新的语言特性,Kotlin Multiplatform、JVM、Native、JS 和 Wasm 的更新,以及 Gradle 和 Maven 的构建工具支持。
关于缺陷修复版本 2.4.10 的详情,请参阅变更日志
Kotlin 2.4.0 发布了!以下是主要亮点:
- 语言:稳定的上下文参数、显式的幕后字段,以及多项注解使用处目标特性
- 标准库:UUID API 支持已稳定以及支持检查有序性
- Kotlin/JVM:支持 Java 26以及默认启用元数据中的注解
- Kotlin/Native:支持把 Swift 包作为依赖、Swift 导出的更新,以及默认启用 CMS GC
- Kotlin/Wasm:默认启用增量编译并支持 WebAssembly Component Model
- Kotlin/JS:支持值类导出,以及在 JS 代码内联时支持 ES2015 特性
- Gradle:与 Gradle 9.5.0 兼容
- Maven:Java 与 JVM 目标版本自动对齐
- Kotlin 编译器:
.klib编译期间内联函数行为更加一致
你也可以通过这个视频了解这些更新的概览:
提示: 关于 Kotlin 发布周期的信息,请参阅 Kotlin 发布流程。
更新到 Kotlin 2.4.0
最新版本的 Kotlin 已包含在最新版本的 IntelliJ IDEA 和 Android Studio 中。
要更新到新的 Kotlin 版本,请确保把 IDE 更新到最新版本,并在构建脚本中把 Kotlin 版本改为 2.4.0。
新特性
稳定
在之前的 Kotlin 版本中,有若干新特性是以实验性形式引入的。以下特性在 Kotlin 2.4.0 中已升级为稳定,因此你不再需要选择启用就能使用它们:
- 上下文参数,但上下文实参和可调用引用除外
- 属性的
@all元目标 - 注解使用处目标的新默认规则
- 显式的幕后字段
- 通用 Kotlin 标准库中稳定的 UUID API
- JVM 上把无符号整数转换为
BigInteger的新 API - 支持检查有序性
- 支持把值类导出到 JavaScript/TypeScript
- 在 JS 代码内联时支持 ES2015 特性
- Maven:Java 与 JVM 目标版本自动对齐
- 支持 Maven Toolchains
新特性
实验性
- 上下文参数的显式上下文实参
- 支持集合字面量
- 改进的编译期常量
- 改进的高阶函数未使用结果检查
- 新的
@IntroducedAt注解,用于为可选参数生成基于版本的重载 - 新的映射回退函数,用于区分
null值与缺失的键 - Swift 包导入
- Swift 导出进入 Alpha,并改进了并发支持
- 支持 WebAssembly Component Model
语言
Kotlin 2.4.0 把上下文参数、显式幕后字段和注解使用处目标特性升级为稳定。本版本还引入了上下文参数的显式上下文实参。
稳定特性
语言
Kotlin 2.2.0 和 2.3.0 以实验性形式引入了一些语言特性。我们很高兴地宣布,以下语言特性在本版本中已稳定:
导入指令的最后一段不再产生弃用警告
语言
在以前的 Kotlin 版本中,导入已弃用的类时,弃用错误既会在调用处报告,也会在 import 指令本身报告。由于无法单独抑制 import 上的弃用错误,你可能只能通过抑制整个文件的弃用报告或使用星号导入来绕过它。
由于在导入被调用的符号时报告弃用信息在大多数情况下并没有用,Kotlin 2.4.0 不再在 import 指令的最后一段引用已弃用符号时发出警告。
更多信息请参阅 KT-30155。
上下文参数的显式上下文实参
实验性
语言
Kotlin 2.4.0 引入了上下文参数的显式上下文实参。
Kotlin 2.3.20 改变了上下文参数的重载解析。其结果是,仅靠上下文参数区分的那几个重载,其调用可能产生歧义。
现在你可以在调用处传入显式的上下文实参来消除这种歧义。
下面是一个示例:
| |
你也可以用显式上下文实参代替 context() 函数,以减少嵌套并让某些调用更易读。如果你需要在多次调用中使用相同的上下文实参,则仍应使用 context() 函数。
该特性属于实验性。要选择启用,请在构建文件中添加以下编译器选项:
Gradle
| |
Maven
| |
更多信息请参阅该特性的 KEEP。
支持集合字面量
实验性
语言
Kotlin 2.4.0 引入了对集合字面量的实验性支持。现在你可以用更简单、更简洁的方括号 [] 来创建集合。
例如:
| |
注意: 目前集合字面量还不能用于构造 Java 中定义的集合。更多信息请参阅 KT-80494。
如果编译器没有足够信息推断集合类型,它会默认使用 List 类型:
| |
你也可以声明自定义的 operator fun of 函数,从而在你自己的类型上使用方括号语法。例如,假设你有下面这个 DoubleMatrix 类:
| |
就可以像这样创建 identityMatrix 类实例:
| |
在这个示例中,编译器把嵌套的集合字面量转换为对相应 operator fun of 函数的调用。编译器会递归解析这些调用,并使用期望的类型来选择正确的重载。
该特性属于实验性。要选择启用,请在构建文件中添加以下编译器选项:
Gradle
| |
Maven
| |
更多信息请参阅该特性的 KEEP。
改进的编译期常量
实验性
语言
Kotlin 2.4.0 为编译期常量带来了实验性改进,让数值类型和字符串类型方面的支持更加一致、更易使用。这些改进包括支持:
- 无符号类型运算。
- 字符串的标准库函数,例如
.lowercase()、.uppercase()和.trim()函数。 - 对枚举常量的
.name属性以及KCallable接口求值。
为了让人们清楚哪些函数会在编译期求值,Kotlin 2.4.0 引入了 IntrinsicConstEvaluation 注解。有些函数会在编译期求值,但还没有该注解。后续版本会为其余函数补上这个注解。受支持函数的列表请参阅 KEEP 的附录。
该特性属于实验性。要选择启用,请在构建文件中添加以下编译器选项:
Gradle
| |
Maven
| |
更多信息请参阅该特性的 KEEP。
改进的高阶函数未使用结果检查
实验性
语言
Kotlin 2.4.0 引入了新的实验性 returnsResultOf() 契约,用来改进未使用返回值检查器。
该契约让检查器能够区分「可以忽略的未使用结果」和「有意义的高阶函数未使用结果」——后者会返回 lambda 的结果,例如 let 作用域函数。
警告: Kotlin 契约属于实验性。要选择启用,请在声明带契约的函数时添加
@OptIn(ExperimentalContracts::class)注解。
要使用该特性,请在函数的契约中添加 returnsResultOf():
| |
下面是一个使用自定义 .customLet() 函数处理可空值的示例:
| |
未使用返回值检查器属于实验性,必须启用后才会报告未使用返回值。关于启用和配置该检查器的更多信息,请参阅未使用返回值检查器。
如何启用
returnsResultOf() 契约属于实验性。请注意,使用它会产生预发布二进制产物,较早版本的 Kotlin 编译器无法读取。要选择启用,请在构建文件中添加以下编译器选项:
Gradle
| |
| |
新的 @IntroducedAt 注解,用于为可选参数生成基于版本的重载
实验性
语言
Kotlin 2.4.0 引入了 @IntroducedAt 注解,用于在向已发布的 API 添加新的可选参数时保持二进制兼容性。
以前,为函数添加可选参数通常需要使用 @JvmOverloads,而它可能生成超出需要的重载。另一种做法是保留旧签名作为隐藏的已弃用重载,以维持二进制兼容性。
有了 @IntroducedAt 注解,你可以为新添加的可选参数标注它们被引入的版本。编译器会利用这些信息自动生成相应的隐藏重载。
该注解属于实验性。要选择启用,请使用 @OptIn(ExperimentalVersionOverloading::class) 注解。
下面是一个示例:
| |
在这个示例中,编译器会为 Button() 函数较早的版本生成隐藏重载。
由于 @IntroducedAt 和 @JvmOverloads 都会生成重载,同时使用它们可能造成重载冲突。如果你同时使用这两个注解,编译器会发出警告。如果你抑制了该警告,编译器会优先采用由 @IntroducedAt 注解生成的重载。
标准库
Kotlin 2.4.0 稳定了通用 Kotlin 标准库中对 UUID 的支持。它还在 JVM 上新增了把无符号整数转换为 BigInteger 的扩展函数,并增加了对检查有序性的支持。
通用 Kotlin 标准库中稳定的 UUID API
标准库
Kotlin 2.0.20 引入了用于生成 UUID(通用唯一标识符)的类,并增加了在 Kotlin UUID 与 Java UUID 之间转换的支持。后续版本逐步改进了这一实验性特性,新增了以下支持:
在 Kotlin 2.4.0 中,kotlin.uuid.Uuid API 已成为稳定。唯一的例外是生成 V4 和 V7 UUID 的函数,它们仍属实验性,仍需要选择启用。
关于如何使用 UUID 的更多信息,请参阅 UUID。
支持检查有序性
标准库
Kotlin 2.4.0 新增了用于检查可迭代对象、数组和序列是否有序的扩展函数。
其中包括以下扩展函数:
.isSorted().isSortedDescending().isSortedWith(comparator).isSortedBy(selector).isSortedByDescending(selector)
你可以用这些扩展函数检查元素是否已经有序,而不必重新排序或自己编写辅助函数。如果元素符合指定的顺序,或者元素少于两个,它们返回 true,否则返回 false。这些函数一遇到不满足顺序的元素对就立即停止,因此对大量输入也很高效。
下面是一个用 .isSorted() 和 .isSortedBy() 函数检查有序性的示例:
| |
JVM 上把无符号整数转换为 BigInteger 的新 API
标准库
Kotlin 2.4.0 在 JVM 上引入了 UInt.toBigInteger() 和 ULong.toBigInteger() 扩展函数。
以前,把 UInt 和 ULong 值转换为 BigInteger 需要基于字符串的变通方案或自定义转换逻辑。从 Kotlin 2.4.0 开始,你可以用 .toBigInteger() 直接把无符号整数值转换为 BigInteger。
下面是一个示例:
| |
新的映射回退函数,用于区分 null 值与缺失的键
实验性
标准库
Kotlin 2.4.0 为值可为空的映射新增了现有 .getOrElse() 和 .getOrPut() 映射扩展函数的变体。这些函数根据键读取值,或以默认值作为回退。对于值可为空的映射,新变体让你可以选择把存储的 null 值当作缺失的键还是当作已存在的值,并且在函数名中清楚地表达这一选择。
新的扩展函数包括:
.getOrElseIfNull(key, defaultValue)和.getOrPutIfNull(key, defaultValue):当键缺失或值为null时返回默认值,与现有的.getOrElse()和.getOrPut()函数类似。.getOrElseIfMissing(key, defaultValue)和.getOrPutIfMissing(key, defaultValue):仅当映射中不包含指定键时才返回默认值。
这些 API 属于实验性,需要使用 @OptIn(ExperimentalStdlibApi::class) 注解选择启用。
下面这个示例演示了当键存在但值为 null 时,.getOrPutIfNull() 与 .getOrPutIfMissing() 的差别:
| |
你也可以把 .getOrElseIfMissing() 和 .getOrPutIfMissing() 函数用于存储可空值的缓存。如果 defaultValue 返回 null,映射会把它存下来,并且不会再为同一个键调用 defaultValue。
下面是一个示例:
| |
欢迎在 YouTrack 上提供反馈。
Kotlin/JVM
Kotlin 2.4.0 支持新的 Java 版本,并默认启用元数据中的注解。
支持 Java 26
JVM
从 Kotlin 2.4.0 开始,编译器可以生成包含 Java 26 字节码的类。
默认启用元数据中的注解
JVM
Kotlin 2.2.0 中的 Kotlin Metadata JVM 库引入了读取存储在 Kotlin 元数据中的注解的支持。有了这项支持,Kotlin 编译器会把注解连同 JVM 字节码一起写入元数据,使 Kotlin Metadata JVM 库可以访问它们。这样一来,注解处理器和其他工具就能在元数据层面理解和操作这些注解,而不必使用反射或修改源码。
在 Kotlin 2.4.0 中,这项支持已默认启用。
Kotlin/Native
从 Kotlin 2.4.0 开始,Swift 导出升级为 Alpha。本版本还带来了对 Swift 包导入、Xcode 26.4 的支持,以及内存占用和垃圾回收方面的改进。
垃圾回收器默认启用并发标记
Native
在 Kotlin 2.0.20 中,Kotlin 团队引入了并发标记清除垃圾回收器(CMS GC)的实验性支持。在收集用户反馈并修复回归问题之后,我们现在准备从 Kotlin 2.4.0 开始默认启用 CMS。
此前垃圾回收器默认采用的并行标记并发清除(PMCS)方案,在 GC 标记堆中对象时必须暂停应用线程。相比之下,CMS 允许标记阶段与应用线程并发运行。
这显著缩短了 GC 暂停时间并提升了应用响应性,对延迟敏感型应用的性能尤为重要。CMS 已经在用 Compose Multiplatform 构建的 UI 应用基准测试中证明了它的有效性。
如果你遇到问题,可以切回 PMCS。为此,请在 gradle.properties 文件中设置以下二进制选项:
kotlin.native.binary.gc=pmcs
关于 Kotlin/Native 垃圾回收器的更多信息,请参阅我们的文档。
降低去虚化分析期间的内存占用
Native
以前,去虚化分析是 Kotlin/Native 编译器中内存占用最高的阶段之一。具体来说,链接发布(link release)任务会消耗过多内存,在大型项目中尤为明显。
Kotlin 2.4.0 引入了一些改进,有助于降低链接发布任务期间的峰值内存占用。
根据我们一位 EAP 用户的基准测试,改进后的去虚化分析让链接发布任务的内存占用减少了一半,至少节省了 13 GB。
支持 Xcode 26.4
Native
从 Kotlin 2.4.0 开始,Kotlin/Native 编译器支持 Xcode 26.4 —— Xcode 最新的稳定版本之一。
现在你可以更新 Xcode,获取最新的 API,继续开发面向 Apple 操作系统的 Kotlin 项目。
LLVM 更新到 21 版
Native
在 Kotlin 2.4.0 中,我们把 LLVM 从 19 版更新到 21 版。新版本包含性能改进,并有助于让 Kotlin/Native 编译器保持最新。
这次更新不应影响你的代码,但如果你遇到任何问题,请在我们的问题跟踪器中报告。
Apple 目标支持的变化
Native
Kotlin 2.4.0 提高了 Apple 目标的默认最低支持版本:
- iOS 和 tvOS:从 14.0 提高到 15.0。
- macOS:从 11.0 提高到 12.0。
- watchOS:从 7.0 提高到 8.0。
如果你的项目需要支持低于默认值的版本,请在构建文件中使用 freeCompilerArgs 选项:
| |
Swift 导出进入 Alpha,并改进了并发支持
Alpha
Native
从 Kotlin 2.4.0 开始,Kotlin 通过 Swift 导出与 Swift 的互操作性正式进入 Alpha!本版本对并发支持做了重大改进,为 Swift 导出加入了原生且直接的结构化并发,并支持把 kotlinx.coroutines 流导出到 Swift。
支持结构化并发
现在你可以从 Swift 无缝调用挂起的 Kotlin 代码。Kotlin 的 suspend 函数和挂起函数类型会导出为 Swift 惯用的 async 对应形式:
| |
| |
把流类型导出到 Swift
这次更新还增加了把 kotlinx.coroutines 流导出到 Swift 的支持。kotlinx.coroutines 中的流表示可以并发发送和消费的异步数据流。它们常用于响应式编程模式,例如监听数据库更新、网络请求或 UI 事件。
以前,把 kotlinx.coroutines.flow 中的 Flow 接口暴露给 Swift 只能借助第三方方案。现在你可以开箱即用地把流导出为 Swift 的惯用对应形式:AsyncSequence。
该特性默认启用。你可以把任何带 Flow 类型的公开 API 导出到 Swift,并保留类型信息。例如:
| |
| |
关于 Swift 导出的更多信息,请参阅我们的文档。
Swift 包导入
实验性
Native
Kotlin Multiplatform 项目现在可以在 Gradle 配置中把 Swift 包声明为 iOS 应用的依赖:
| |
完整示例和更详细的信息请参阅 SwiftPM 导入。
如果你的项目依赖 CocoaPods,可以把现有配置迁移为使用 Swift 包。KMP 工具链考虑到了这种场景,会帮助你自动重新配置项目。详情请参阅我们的 CocoaPods 迁移指南。
Kotlin/Wasm
Kotlin 2.4.0 为 Kotlin/Wasm 默认启用增量编译,并引入了对 WebAssembly Component Model 的支持。
默认启用增量编译
Wasm
Kotlin/Wasm 在 Kotlin 2.1.0 中引入了增量编译。从 Kotlin 2.4.0 开始,它已稳定并默认启用。有了这个特性,编译器只重新构建受近期改动影响的文件,从而显著缩短构建时间。
要停用增量编译,请在项目的 local.properties 或 gradle.properties 文件中添加以下内容:
# gradle.properties
kotlin.incremental.wasm=false
如果你遇到任何问题,请在 YouTrack 中报告。
改进 Chrome DevTools 中内部变量的显示
Wasm
Kotlin 2.4.0 改进了在 Chrome DevTools 中调试 Kotlin/Wasm 的体验,让临时变量、合成变量和内部变量更容易与用户定义的变量区分开来。
Kotlin 编译器和诸如 Compose 之类的编译器插件都可能生成这些变量。它们现在默认使用 ~ 前缀,因此会被归为一组,并移动到变量列表末尾(Chrome DevTools 按名称排序)。
支持 WebAssembly Component Model
实验性
Wasm
Kotlin/Wasm 在 Kotlin 2.4.0 中更进一步,引入了对 WebAssembly Component Model 的实验性支持。该提案定义了一种通过标准化接口和类型从 Wasm 模块构建组件的方式。这种做法有助于 Wasm 从底层的二进制指令格式演变为可组合、与语言无关的可复用组件体系。它让 Kotlin/Wasm 能够走出浏览器。例如,Kotlin 和 WebAssembly 非常适合函数即服务(Function-as-a-Service,也称为 FaaS 或无服务器)应用。
要试用该特性,请查看一个用 wasi:http 构建的简单服务器。

欢迎在 YouTrack 中分享反馈。
Kotlin/JS
Kotlin 2.4.0 进一步改进了到 JavaScript/TypeScript 的导出,包括支持导出值类、接口和类型型变,以及在 JS 代码内联时支持 ES2015 特性。
支持把值类导出到 JavaScript/TypeScript
Js
以前只有普通的 Kotlin 类可以导出到 JavaScript/TypeScript。Kotlin 2.4.0 取消了这个限制。现在你可以把 Kotlin 的内联值类导出为普通的 TypeScript 类。
要导出值类,请在 Kotlin 一侧用 @JsExport 注解标记它:
| |
在 TypeScript 一侧,它看起来就像一个普通的类:
| |
更多信息请参阅 @JsExport 注解。
内联 JS 代码时支持 ES2015 特性
Js
从 Kotlin 2.4.0 开始,JavaScript 代码内联完整支持 ES2015 特性。
这对与第三方库的互操作很有用,也便于直接控制自动生成的应用代码。
现在你可以在 js() 调用中使用现代 JS 特性,包括:
const和let变量声明- ES 类
- 生成器
- lambda(箭头函数)
- 展开与剩余运算符
- 模板字符串
请记住,js() 函数的参数必须是字符串常量,因为它会在编译期被解析并「原样」转换为 JavaScript 代码。例如,要内联展开运算符,可以这样写:
| |
关于内联 JavaScript 代码的更多信息,请参阅我们的文档。
导出到 TypeScript 时保留类型型变
Js
以前,把类型导出到 TypeScript 时,泛型位置上的 Kotlin 型变信息会丢失。
在 Kotlin 2.4.0 中,型变注解在导出时会被保留,并映射到 TypeScript 的型变注解。
在你的 Kotlin 代码中定义泛型类型参数的型变:
| |
使用 Kotlin 2.4.0,生成的 TypeScript 输出会保留 in 和 out 关键字:
| |
改进到 JavaScript/TypeScript 的接口导出
Js
Kotlin 2.4.0 让把 Kotlin 接口导出到 JavaScript/TypeScript 变得更加方便。
新的 @JsNoRuntime 注解去掉了实现 Kotlin 接口所需的元数据,从而可以直接映射为普通的 TypeScript 接口,与外部接口默认的行为类似。
要导出 Kotlin 接口,例如在 Kotlin Multiplatform 项目中,在公共代码中用 @JsNoRuntime 注解标记它:
| |
然后在 JS 专属源码中提供 actual 实现:
| |
由于实现 Kotlin 接口所需的元数据被移除,该接口会映射为普通的 TypeScript 接口:
| |
@JsNoRuntime 注解只允许用在标准接口上,这样 TypeScript 才能把 Kotlin 接口当作普通 TypeScript 接口处理。因此,以下操作会被禁止:
is和as类型检查。- 使用
::class语法的类引用。 - 把接口作为具体化(reified)类型实参传递。
避免对外部接口使用
@JsNoRuntime注解,因为这样会产生编译器警告。
放宽导出接口的限制
实验性
Js
Kotlin 2.4.0 朝着 @JsExport 的稳定化又迈进了一步,改进了 Kotlin 接口的导出方式。
现在你可以导出带嵌套类和具名伴生对象的 Kotlin 接口:
| |
更多信息请参阅 @JsExport 注解。
Gradle
Kotlin 2.4.0 与 Gradle 7.6.3 到 9.5.0 完全兼容。你也可以使用更高版本的 Gradle,最高可到最新的 Gradle 发行版。不过请注意,这样做可能会产生弃用警告,而且某些新的 Gradle 特性可能无法使用。Kotlin 2.4.0 还带来了诸如跨平台一致的默认模块名、以及为 Kotlin/JVM 把编译器消息写入 Problems API 等改进。
最低支持的 AGP 版本提升到 8.5.2
Gradle
从 Kotlin 2.4.0 开始,最低支持的 Android Gradle 插件版本是 8.5.2。
跨平台一致的模块名
Gradle
在 Kotlin 2.4.0 之前,各平台的默认模块名各不相同。这种不一致可能造成命名冲突和解析问题。Kotlin 2.4.0 把各平台的默认名称统一为 {group}:{project_name}。
如果你需要把 JVM 模块名恢复为以前的版本,请在 Kotlin/JVM 项目的 build.gradle.kts 文件中添加:
| |
对于多平台项目:
| |
Kotlin/JVM 的编译器消息写入 Problems API
Gradle
在 Kotlin 2.2.0 中,Kotlin Gradle 插件(KGP)开始把诊断信息报告给 Gradle 的 Problems API,以便在 Gradle 命令行和 IntelliJ IDEA 中提供一致的体验。
在 Kotlin 2.4.0 中,该插件还会为 Kotlin/JVM 把编译器消息写入 Problems API,让这个 API 更接近成为所有日志和消息的唯一来源。
Maven
Kotlin 2.4.0 通过支持 Maven Toolchains 以及 Java 与 JVM 目标版本自动对齐,让项目配置更加简单。
Java 与 JVM 目标版本自动对齐
Maven
为简化项目配置并避免兼容性问题,Kotlin Maven 插件现在会自动把 JVM 目标版本与项目中配置的 Java 编译器版本对齐。
这能确保 Kotlin 和 Maven 编译器以相同的字节码版本为目标,避免出现 Kotlin 生成的字节码与项目其余部分或预期部署环境不兼容的问题。
启用 <extensions> 选项后,你不需要再设置 kotlin.compiler.jvmTarget 或 kotlin.compiler.jdkRelease 选项。如果这两个都没有定义,Kotlin Maven 插件会按以下顺序自动解析 JVM 目标版本:
- 使用
maven.compiler.release版本,它既可以定义在项目属性中,也可以定义在maven-compiler-plugin配置中。
在这种情况下,会为 Kotlin 编译器同时设置 jvmTarget 和 jdkRelease 两个编译器选项,从而把 API 限制到特定的 JDK 版本。
- 如果未设置 Maven release 版本,则使用
maven.compiler.target版本。编译器 target 既可以定义在项目属性中,也可以定义在maven-compiler-plugin配置中。
在这种情况下,只设置 Kotlin 的 jvmTarget,API 不会被限制到特定的 JDK 版本。
这大大简化了 Kotlin 项目的配置,你的 pom.xml 文件可以写成这样:
| |
在构建过程中,插件会输出类似这样的消息:
[INFO] Using jvmTarget=17 (derived from maven.compiler.release=17)
注意:
<extensions>选项只检查项目级属性和全局的maven-compiler-plugin配置。它不会检查插件<executions>部分中定义的配置。
关于项目自动配置的更多信息,请参阅我们的文档。
支持 Maven Toolchains
Maven
Kotlin 2.4.0 为 Kotlin Maven 插件引入了对 Maven Toolchains 的支持。
该特性有助于管理构建中使用的 JDK 版本。借助 Maven Toolchains,你可以指定用于 Kotlin 编译的 JDK 版本,而不受运行 Maven 的 JVM 版本(在 JAVA_HOME 中设置)影响。当构建中配置了 maven-toolchains-plugin 时,Kotlin Maven 插件会像 Maven 编译器插件和其他 Maven 插件一样,自动采用所选的 JDK toolchain。这样你就可以配置一个统一的 toolchain,用它控制构建中所有插件(包括 Kotlin 编译)所使用的 JDK:
| |
请记住设置 JDK 版本的不同方式之间的优先级:
kotlin-maven-plugin配置中的jdkHome。显式设置的jdkHome选项总是优先于 toolchain 版本。maven-toolchains-plugin中的 JDK 版本。通过 Maven Toolchains 设置的 JDK 版本会覆盖JAVA_HOME路径中设置的 JDK 版本。JAVA_HOME路径。
你也可以使用插件专用的 <jdkToolchain> 选项,直接在 kotlin-maven-plugin 的 toolchain 中设置 JDK 版本。与使用 maven-toolchains-plugin 相比,这个参数只影响 Kotlin 编译,对构建中的其他插件没有影响。
注意: 目前把
maven-toolchains-plugin设置为使用特定 JDK 版本并不会影响kotlin-maven-plugin的kapt和test-kaptgoal。变通做法是在JAVA_HOME路径中设置所需版本。更多细节请参阅 KT-79897。
关于配置 Kotlin Maven 项目的更多信息,请参阅我们的文档。
构建工具 API
Bta
Kotlin 2.4.0 为构建工具 API(BTA)带来了多项改进。BTA:
- 为大多数 JVM 和通用编译器选项引入了新的类型安全抽象。BTA 现在负责处理它们的格式,而不是由客户端处理,从而降低出错风险并提供额外一层协助。这一变化在运行时向后兼容,但可能破坏源码兼容性。
- 现在可以在增量编译中跟踪非源码变化,例如配置不同的 Kotlin 版本或修改编译器选项。构建系统可以通过
BaseIncrementalCompilationConfiguration.TRACK_CONFIGURATION_INPUTS选项控制这一行为。 - 通过
AbiValidationToolchain支持二进制兼容性验证,让其他构建系统更容易加入这一功能。 - 引入新特性,让构建系统可以通过
CompilerMessageRenderer接口和JvmCompilationOperation构建器自定义编译器消息的显示方式。 - 引入用于配置 Kotlin 守护进程日志的新选项:
LOGS_PATH—— 守护进程日志文件所在目录。LOGS_FILE_SIZE_LIMIT—— 日志文件的最大字节数。LOGS_FILE_COUNT_LIMIT—— 保留的日志文件数量上限。
默认情况下,这些上限被设置为特定于 Kotlin 编译器版本的值。若要取消限制,构建工具必须把该选项设为 null。
构建系统可以在配置执行策略时设置该选项:
| |
Kotlin 编译器
Kotlin 2.4.0 让同一模块中声明的内联函数在 .klib 编译期间的行为更加一致。
klib 编译期间同一模块内函数内联行为的一致性
编译器
以前,函数内联在不同 Kotlin 平台上的行为并不一致。JetBrains 团队正努力在所有受支持的平台上统一这一行为,以确保提供相同的兼容性保证。
在 Kotlin/JVM 上,函数内联发生在编译期。因此,用 Kotlin/JVM 编译器编译 Kotlin 源码时,生成的 class 文件字节码中不会保留内联函数调用,因为内联函数体已经被内联到调用处,其行为在编译期就已经固定。
相反,在 Kotlin/Native、Kotlin/JS 和 Kotlin/Wasm 上,函数内联并不发生在源码到 klib 的编译阶段,而只在生成二进制产物时发生。因此,内联函数的行为在 .klib 编译期间并未固定,.klib 库无法像 Kotlin/JVM 那样为内联函数提供相同的兼容性保证。
Kotlin 2.4.0 迈出了统一内联函数行为的第一步:在生成 .klib 产物时启用同一模块内的内联:
| |
| |
编译为 .klib 后,代码大致如下:
| |
这意味着只有同一模块中声明的内联函数会在 .klib 编译期间被内联。其他函数(本例中就是另一个模块里的那个)会在生成平台特定二进制产物时内联。
如何启用
从 2.4.0 开始,同一模块内内联在 Kotlin/Native、Kotlin/JS 和 Kotlin/Wasm 上默认启用。
如果你在这个特性上遇到意外问题,可以用命令行中的以下编译器选项停用它:
| |
下一步是启用跨模块内联,以确保项目中所有内联函数都能一致地内联。这一变化计划在未来的 Kotlin 版本中推出,但你现在就可以用命令行中的以下编译器选项试用:
| |
欢迎在 YouTrack 中分享反馈并报告任何问题。
各 Kotlin 编译器之间一致的部分库链接
编译器
在 Kotlin 1.9.0 中,部分库链接(partial library linkage)在 Kotlin/Native 和 Kotlin/JS 编译器上默认启用,Kotlin/Wasm 在 Kotlin 2.0.0 中跟进。该特性实际上让编译器以与 Kotlin/JVM 一致的方式处理 Kotlin 库中的链接问题。
此后我们没有收到负面反馈,也没有发现有人在项目中停用部分链接。因此从 Kotlin 2.4.0 开始,部分链接始终启用,-Xpartial-linkage 编译器选项现已弃用。
所有 Kotlin 编译器的默认日志级别是 SILENT。编译期间不会报告链接问题。要在项目中改变这一行为,请在构建文件中设置 -Xpartial-linkage-loglevel 编译器选项:
| |
INFO以 “info” 日志级别报告链接问题。WARNING在编译期报告警告,并把它们记录到编译日志中。ERROR在出现链接问题时让编译失败,并在编译日志中报告错误。需要更仔细地检查链接问题时可以使用这个选项。
如果你在这个特性上遇到问题,请在我们的问题跟踪器中报告。
Kotlin 编译器插件
在 Kotlin 2.4.0 中,Kotlin 编译器插件也获得了显著的更新。kapt 插件现在可以把不必要的注解处理器排除在编译类路径之外,Power-assert 插件则通过新的运行时库提供了更简单的配置方式。
kapt:从编译类路径中排除注解处理器
Kotlin 2.4.0 为注解处理器发现机制增加了对 includeCompileClasspath 配置选项的支持,与 Kotlin Gradle 插件类似。这个新选项让你可以把不必要的注解处理器排除在编译类路径之外。
要在构建文件中配置它,请在 kapt 插件的 <execution> 部分把 includeCompileClasspath 选项设为 false:
| |
或者,你也可以在 <properties> 部分通过 kapt.include.compile.classpath 达到同样效果:
| |
当该选项设为 false 时,未包含在 kapt 配置 <annotationProcessorPaths> 部分中的注解处理器会被排除在 kapt 处理之外。
如果没有设置 includeCompileClasspath,而 kapt 在编译类路径上发现了未在 <annotationProcessorPaths> 部分中显式定义的注解处理器,你会看到以下弃用警告:
| |
关于 kapt 配置的更多信息,请参阅我们的文档。
Power-assert:新的运行时库
Kotlin 2.4.0 通过新的运行时库,让支持 Power-assert 的函数更容易被发现、也更容易配置。
以前,采用 Power-assert 需要复杂的构建配置和函数参数约定。从本版本开始,支持 Power-assert 的函数可以使用新的运行时库,直接与编译器插件的转换集成。
这为插件用户和库作者都带来了重大改进:
- 新的
CallExplanation数据结构提供关于调用处的详细信息。这使得断言失败时可以渲染更动态的示意图,并能更好地与外部工具集成。 - 新的
@PowerAssert注解让断言函数可以被编译器插件立即发现。这样你就可以在自己的库中开箱即用地支持 Power-assert。
提示: 可以使用我们的示例集合作为试验这些新特性的演练场。
更多信息请参阅我们的文档。
Compose 编译器
在 Kotlin 2.4.0 中,Compose 编译器提供了更一致的增量编译,并推进了若干特性标志的弃用周期。
内部声明增量编译的一致性
Compose 编译器
从 Kotlin 2.4.0 开始,Compose 编译器提供了更一致的增量编译。不同文件之间内部类型的稳定性现在会在运行时推断。这让 Compose 即使在没有重新编译类使用处的情况下,也能更新推断出的稳定性值。
副作用是:当某个 @Composable 函数把来自另一个文件的 internal 类用作参数时,你的产物体积可能增大。这是因为稳定性必须在运行时决定,编译器会为稳定和不稳定两种情况都编码执行路径。执行全应用优化的压缩工具(例如 R8)能够推断出多余的执行路径并将其消除,因此这种运行期稳定性的开销会被去除。
这次更新不会改变最终的稳定性值,因此 @Composable 函数的行为保持不变。
特性标志弃用
Compose 编译器
Kotlin 2.4.0 推进了若干已升级为稳定并默认启用的实验性特性标志的弃用周期:
StrongSkipping、IntrinsicRemember及相关的 DSL 属性被提升为DeprecationLevel.ERROR。它们将在 Kotlin 2.5.0 中移除。OptimizeNonSkippingGroups和PausableComposition现已弃用。它们计划在 Kotlin 2.6.0 中移除。
破坏性变更与弃用
本节重点介绍重要的破坏性变更和弃用。完整概览请参阅我们的兼容性指南。
- 从 Kotlin 2.4.0 开始,编译器不再支持
-language-version=1.9。因此 K1 编译器不再受支持。 - Kotlin 2.4.0 精简了 Kotlin Gradle 插件中二进制兼容性验证的 DSL,并弃用了部分内容。最新 DSL 请参阅 Kotlin Gradle 插件中的二进制兼容性验证。
- 通过
KotlinScriptMojoMaven 插件执行 Kotlin 脚本的支持已被移除。
文档更新
我们在 Kotlin 生态中做了以下文档改动:
- Compose Multiplatform 应用中的 Liquid Glass —— 把 iOS 应用从完全由 Compose 驱动的导航迁移到使用 iOS 26 Liquid Glass 样式的原生 SwiftUI 导航。
- 把 Swift 包作为依赖添加到 KMP 模块 —— 了解如何在你的 KMP 项目中设置 SwiftPM 依赖。
- 手动或借助 Junie把 Kotlin Multiplatform 项目从 CocoaPods 依赖切换到 SwiftPM 依赖 —— 了解如何使用 Junie 和 Kotlin AI 技能让迁移更容易。
- 为 KMP 应用配置 TeamCity —— 使用 TeamCity 构建、测试并部署你的 KMP 应用。
- Navigation 3 的推荐序列化方式 —— 找到在你的 CMP 应用中配合 Navigation 3 使用序列化的最佳方式。
- 多平台 ViewModel —— 了解如何在多平台项目中设置和使用 ViewModel。
- 用 Kotlin 进行后端开发 —— 探索可用于后端开发的各种框架。
- 用 Spring Boot 和 Claude 创建任务管理应用 —— 了解 Claude 如何帮你从零开始用 Spring Boot 创建应用。
- 配置 Maven 项目 —— 在你现有的 Java Maven 项目或新的 Kotlin Maven 项目中设置 Kotlin 编译。
- 用 Maven 测试 Kotlin 项目 —— 了解如何用 JUnit 编写测试,并用 Maven 插件运行单元测试和集成测试。
- 在 Kotlin 项目中使用注解处理器 —— 在后端项目中在 kapt 和 KSP 之间做选择来处理注解。
- Kotlin AI 技能 —— 使用代理技能帮你完成 Kotlin 相关的任务。
- Kotlin Language Server —— 了解 JetBrains 官方的 Kotlin 语言服务器协议(LSP)实现。
- 数值 —— 探索 Kotlin 的数值类型以及如何使用它们。
- KSP 入门 —— 了解如何把基于 KSP 的处理器加入项目,或创建自己的处理器。
- 从 kapt 迁移到 KSP —— 迁移你的注解处理器,以充分利用 Kotlin 的特性。
- Lincheck 概览 —— 理解 Lincheck 在幕后如何测试 JVM 上的并发代码。
- Lincheck 入门 —— 创建项目并使用 Lincheck 运行测试。
- 用 Lincheck 测试任意代码 —— 了解如何用 Lincheck 测试并发代码。
- 如何用 Lincheck 测试数据结构 —— 深入了解 Lincheck 的数据结构测试流程。
- Lincheck 的测试策略 —— 了解 Lincheck 的测试策略:模型检查与压力测试。
- 配置 Lincheck 的测试策略 —— 探索 Lincheck 测试策略的各项选项。
- 用 Dokku 部署 Ktor 应用 —— 了解使用 Dokku 的部署工作流。