13.6.7.2 Kotlin 1.7.0 新变化
22 分钟阅读
13.6.7.2 Kotlin 1.7.0 新变化
阅读 Kotlin 1.7.0 发行说明,了解新的语言特性,以及 Kotlin Multiplatform、JVM、Native、JS 的更新和 Gradle、Maven 的构建工具支持。
Kotlin 1.7.0 的 IDE 支持适用于 IntelliJ IDEA 2021.2、2021.3 和 2022.1。
Kotlin 1.7.0 已经发布。它揭开了新 Kotlin/JVM K2 编译器 Alpha 版的面纱,稳定了多项语言特性,并为 JVM、JS 和 Native 平台带来了性能改进。
以下是此版本中的主要更新列表:
- 新的 Kotlin K2 编译器现在处于 Alpha 阶段,它带来了显著的性能改进。它仅适用于 JVM,并且包括 kapt 在内的任何编译器插件都无法与它配合使用。
- Gradle 中增量编译的新方式。增量编译现在还支持依赖的非 Kotlin 模块中的变更,并且与 Gradle 兼容。
- 我们稳定了选择启用要求注解、明确非可空类型和构建器推断。
- 现在类型实参有了下划线运算符。当其他类型已指定时,你可以用它自动推断某个实参的类型。
- 此版本允许通过委托给内联类的内联值来实现接口。现在你可以创建在大多数情况下不分配内存的轻量级包装器。
你也可以在这个视频中查看这些变更的简短概述:
提示: 有关 Kotlin 发布周期的信息,请参见 Kotlin 发布流程。
JVM 版新 Kotlin K2 编译器进入 Alpha
此 Kotlin 版本引入了新的 Kotlin K2 编译器的 Alpha 版。新编译器旨在加快新语言特性的开发、统一 Kotlin 支持的所有平台、带来性能改进,并提供用于编译器扩展的 API。
我们已经发布了一些关于新编译器及其优势的详细说明:
需要指出的是,在新 K2 编译器的 Alpha 版中我们主要关注性能改进,而且它只适用于 JVM 项目。它不支持 Kotlin/JS、Kotlin/Native 或其他多平台项目,并且包括 kapt 在内的任何编译器插件都无法与它配合使用。
我们的基准测试在内部项目上显示了一些出色的结果:
| 项目 | 当前 Kotlin 编译器性能 | 新 K2 Kotlin 编译器性能 | 性能提升 |
| Kotlin | 2.2 KLOC/s | 4.8 KLOC/s | 约 x2.2 | | YouTrack | 1.8 KLOC/s | 4.2 KLOC/s | 约 x2.3 | | IntelliJ IDEA | 1.8 KLOC/s | 3.9 KLOC/s | 约 x2.2 | | Space | 1.2 KLOC/s | 2.8 KLOC/s | 约 x2.3 |
KLOC/s 性能数字代表编译器每秒处理的代码行数(以千行为单位)。 {style=“tip”}
你可以在自己的 JVM 项目上检验性能提升,并与旧编译器的结果进行比较。要启用 Kotlin K2 编译器,请使用以下编译器选项:
| |
此外,K2 编译器包含大量缺陷修复。请注意,即使该列表中状态为 Open 的议题实际上也已在 K2 中修复。
接下来的 Kotlin 版本将继续提升 K2 编译器的稳定性并提供更多特性,敬请期待!
如果你在使用 Kotlin K2 编译器时遇到任何性能问题,请向我们的问题跟踪器报告。
语言
Kotlin 1.7.0 引入了对委托实现的支持以及用于类型实参的新下划线运算符。它还稳定了此前版本中作为预览引入的若干语言特性:
允许通过委托给内联类的内联值实现接口
如果你想为某个值或类实例创建轻量级包装器,就必须手工实现所有接口方法。委托实现可以解决这个问题,但在 1.7.0 之前它无法与内联类一起使用。这一限制已被移除,因此你现在可以创建在大多数情况下不分配内存的轻量级包装器。
| |
类型实参的下划线运算符
Kotlin 1.7.0 引入了用于类型实参的下划线运算符 _。当其他类型已指定时,你可以用它自动推断类型实参:
| |
注意: 你可以在变量列表中的任何位置使用下划线运算符来推断类型实参。
稳定的构建器推断
构建器推断是一种特殊的类型推断,在调用泛型构建器函数时很有用。它利用 lambda 实参内部其他调用的类型信息,帮助编译器推断调用的类型实参。
从 1.7.0 开始,如果常规类型推断在未指定 -Xenable-builder-inference 编译器选项的情况下无法获得足够的类型信息,构建器推断就会自动启用,该编译器选项在 1.6.0 中引入。
稳定的选择启用要求
选择启用要求现在已进入 Stable,并且不需要额外的编译器配置。
在 1.7.0 之前,选择启用特性本身需要参数 -opt-in=kotlin.RequiresOptIn 才能避免警告。现在不再需要这样做;不过你仍然可以使用编译器参数 -opt-in 来为其他注解、模块选择启用。
稳定的明确非可空类型
在 Kotlin 1.7.0 中,明确非可空类型已提升为 Stable。它们在继承泛型 Java 类和接口时提供更好的互操作性。
你可以在使用处用新语法 T & Any 把泛型类型参数标记为明确非可空。该语法形式来自交集类型的写法,目前限于 & 左侧是带可空上界的类型参数、右侧是非可空的 Any:
| |
请在这个 KEEP 中进一步了解明确非可空类型。
Kotlin/JVM
此版本为 Kotlin/JVM 编译器带来了性能改进和一个新的编译器选项。此外,对函数式接口构造器的可调用引用已进入 Stable。请注意,从 1.7.0 起,Kotlin/JVM 编译的默认目标版本是 1.8。
编译器性能优化
Kotlin 1.7.0 为 Kotlin/JVM 编译器引入了性能改进。根据我们的基准测试,与 Kotlin 1.6.0 相比,编译时间平均减少 10%。由于字节码后处理的改进,大量使用内联函数的项目(例如使用 kotlinx.html 的项目)会编译得更快。
新编译器选项:-Xjdk-release
Kotlin 1.7.0 引入了新的编译器选项 -Xjdk-release。该选项类似于 javac 的命令行 --release 选项。-Xjdk-release 选项控制目标字节码版本,并把类路径中 JDK 的 API 限制为指定的 Java 版本。例如,即使依赖中的 JDK 是 9 或更高版本,kotlinc -Xjdk-release=1.8 也不允许引用 java.lang.Module。
注意: 该选项并不保证对每个 JDK 发行版都有效。
请在这个 YouTrack 议题中留下你的反馈。
稳定的对函数式接口构造器的可调用引用
对函数式接口构造器的可调用引用现在已进入 Stable。了解如何通过可调用引用迁移带构造器函数的接口到函数式接口。
请把发现的任何问题报告到 YouTrack。
移除 JVM 目标版本 1.6
Kotlin/JVM 编译的默认目标版本是 1.8。1.6 目标已被移除。
请迁移到 JVM 目标 1.8 或更高版本。了解如何更新以下场景的 JVM 目标版本:
Kotlin/Native
Kotlin 1.7.0 包含对 Objective-C 和 Swift 互操作的更改,并稳定了此前版本中引入的特性。它还为新的内存管理器带来了性能改进以及其他更新:
- 新内存管理器的性能改进
- 与 JVM 和 JS IR 后端统一的编译器插件 ABI
- 支持独立的 Android 可执行文件
- 与 Swift async/await 的互操作:返回
Void而不是KotlinUnit - 禁止通过 Objective-C 桥接的未声明异常
- 改进的 CocoaPods 集成
- 覆盖 Kotlin/Native 编译器下载 URL
新内存管理器的性能改进
注意: 新的 Kotlin/Native 内存管理器处于 Alpha 阶段。它可能会以不兼容的方式发生变化,并在将来需要手动迁移。我们欢迎你在 YouTrack 中提供反馈。
新的内存管理器仍处于 Alpha 阶段,但正在走向 Stable。此版本为新内存管理器带来了显著的性能改进,尤其是在垃圾回收(GC)方面。特别是在 1.6.20 中引入的清理阶段并发实现现在已默认启用。这有助于缩短应用因 GC 而暂停的时间。新的 GC 调度器在选择 GC 频率方面表现更好,尤其是对较大的堆。
此外,我们还专门优化了 debug 二进制文件,确保内存管理器的实现代码使用合适的优化级别和链接时优化。这帮助我们在基准测试中把 debug 二进制的执行时间改善了大约 30%。
请在你的项目中使用新的内存管理器,看看它的效果,并在 YouTrack 中与我们分享反馈。
与 JVM 和 JS IR 后端统一的编译器插件 ABI
从 Kotlin 1.7.0 开始,Kotlin Multiplatform Gradle 插件默认对 Kotlin/Native 使用可嵌入的编译器 jar。这一特性在 1.6.0 中作为实验性特性宣布,现在已进入 Stable,可以放心使用。
这项改进对库作者非常方便,因为它改善了编译器插件的开发体验。在此版本之前,你必须为 Kotlin/Native 提供单独的制品,而现在你可以对 Native 和其他受支持的平台使用相同的编译器插件制品。
警告: 该特性可能需要插件开发者对现有插件采取迁移步骤。请在这个 YouTrack 议题中了解如何为更新做好准备。
支持独立的 Android 可执行文件
Kotlin 1.7.0 为 Android Native 目标生成标准可执行文件提供了完整支持。该特性在 1.6.20 中引入,现在已默认启用。
如果你想回退到 Kotlin/Native 生成共享库的旧行为,请使用以下设置:
| |
与 Swift async/await 的互操作:返回 Void 而不是 KotlinUnit
Kotlin 的 suspend 函数现在在 Swift 中返回 Void 类型而不是 KotlinUnit。这是与 Swift 的 async/await 互操作改进的结果。该特性在 1.6.20 中引入,此版本默认启用了这一行为。
你不再需要使用 kotlin.native.binary.unitSuspendFunctionObjCExport=proper 属性来为这类函数返回正确的类型。
禁止通过 Objective-C 桥接的未声明异常
当你从 Swift/Objective-C 代码调用 Kotlin 代码(或反之)并且该代码抛出异常时,异常应由发生异常的代码处理,除非你通过合适的转换(例如使用 @Throws 注解)明确允许异常在语言之间传递。
以前,Kotlin 还有另一种非预期的行为:未声明的异常在某些情况下会从一个语言“泄漏”到另一个语言。Kotlin 1.7.0 修复了该问题,现在这类情况会导致程序终止。
例如,如果你在 Kotlin 中有一个 { throw Exception() } lambda 并从 Swift 调用它,在 Kotlin 1.7.0 中,异常一旦到达 Swift 代码就会终止程序。在之前的 Kotlin 版本中,这样的异常可能泄漏到 Swift 代码中。
@Throws 注解的行为与之前保持一致。
改进的 CocoaPods 集成
从 Kotlin 1.7.0 开始,如果你想在项目中集成 CocoaPods,不再需要安装 cocoapods-generate 插件。
以前,你需要同时安装 CocoaPods 依赖管理器和 cocoapods-generate 插件才能使用 CocoaPods,例如在 Kotlin Multiplatform Mobile 项目中处理 iOS 依赖。
现在设置 CocoaPods 集成更简单了,我们也解决了 cocoapods-generate 无法在 Ruby 3 及更高版本上安装的问题。现在也支持在 Apple M1 上表现更好的最新 Ruby 版本。
请参阅如何完成初始 CocoaPods 集成。
覆盖 Kotlin/Native 编译器下载 URL
从 Kotlin 1.7.0 开始,你可以自定义 Kotlin/Native 编译器的下载 URL。当 CI 中禁止使用外部链接时,这会很有用。
要覆盖默认基础 URL https://download.jetbrains.com/kotlin/native/builds,请使用以下 Gradle 属性:
kotlin.native.distribution.baseDownloadUrl=https: // 覆盖默认基础 URL 以自定义下载地址
注意: 下载器会把 native 版本和目标操作系统追加到这个基础 URL 后面,以确保下载到实际的编译器发行版。
Kotlin/JS
Kotlin/JS 在 JS IR 编译器后端方面获得了进一步改进,以及其他可以改善开发体验的更新:
- 新 IR 后端的性能改进
- 使用 IR 时的成员名称压缩
- IR 后端通过 polyfill 支持旧版浏览器
- 从 js 表达式动态加载 JavaScript 模块
- 为 JavaScript 测试运行器指定环境变量
新 IR 后端的性能改进
此版本有一些应当能改善你开发体验的重要更新:
- Kotlin/JS 的增量编译性能已显著提升。构建 JS 项目所需的时间更少。在许多情况下,增量重建现在应该大致与旧后端相当。
- Kotlin/JS 的最终包体积更小,因为我们大幅减小了最终制品的体积。在某些大型项目上,我们测量到生产包体积相比旧后端减少了多达 20%。
- 接口的类型检查改善了若干个数量级。
- Kotlin 生成的 JS 代码质量更高
使用 IR 时的成员名称压缩
Kotlin/JS IR 编译器现在利用其关于 Kotlin 类与函数关系的内部信息来应用更高效的压缩,缩短函数、属性和类的名称。这会减小最终打包应用的体积。
当你在生产模式下构建 Kotlin/JS 应用时,这种压缩会自动应用,并且默认启用。要禁用成员名称压缩,请使用 -Xir-minimized-member-names 编译器标志:
| |
IR 后端通过 polyfill 支持旧版浏览器
Kotlin/JS 的 IR 编译器后端现在包含与旧后端相同的 polyfill。这使使用新编译器编译的代码可以在不支持 Kotlin 标准库所用全部 ES2015 方法的旧版浏览器中运行。最终包中只会包含项目实际用到的那些 polyfill,从而把对包体积的潜在影响降到最低。
使用 IR 编译器时该特性默认启用,你无需进行配置。
从 js 表达式动态加载 JavaScript 模块
在处理 JavaScript 模块时,大多数应用使用静态导入,其用法在 JavaScript 模块集成中已有介绍。然而,Kotlin/JS 一直缺少在应用运行时动态加载 JavaScript 模块的机制。
从 Kotlin 1.7.0 开始,js 块中支持来自 JavaScript 的 import 语句,让你可以在运行时把包动态引入应用:
| |
为 JavaScript 测试运行器指定环境变量
要调整 Node.js 包解析或向 Node.js 测试传递外部信息,你现在可以指定 JavaScript 测试运行器使用的环境变量。要定义环境变量,请在构建脚本的 testTask 块内使用带键值对的 environment() 函数:
| |
标准库
在 Kotlin 1.7.0 中,标准库经历了大量变更和改进。它们引入了新特性、稳定了实验性特性,并统一了 Native、JS 和 JVM 对命名捕获组的支持:
- min() 和 max() 集合函数恢复为非可空返回
- 在指定索引处进行正则表达式匹配
- 扩展对以往语言和 API 版本的支持
- 通过反射访问注解
- 稳定的深度递归函数
- 默认时间源基于内联类的时间标记
- Java Optional 的新实验性扩展函数
- JS 和 Native 中对命名捕获组的支持
min() 和 max() 集合函数恢复为非可空返回
在 Kotlin 1.4.0 中,我们把集合函数 min() 和 max() 重命名为 minOrNull() 和 maxOrNull()。这些新名称更好地反映了它们的行为——如果接收者集合为空则返回 null。它还有助于让这些函数的行为与 Kotlin 集合 API 中通用的命名约定保持一致。
minBy()、maxBy()、minWith() 和 maxWith() 也是如此,它们在 Kotlin 1.4.0 中都有了 *OrNull() 同义词。受此变更影响的旧函数被逐步弃用。
Kotlin 1.7.0 重新引入了原来的函数名,但返回类型为非可空。新的 min()、max()、minBy()、maxBy()、minWith() 和 maxWith() 函数现在严格返回集合元素,否则抛出异常。
| |
在指定索引处进行正则表达式匹配
在 1.5.30 中引入的 Regex.matchAt() 和 Regex.matchesAt() 函数现在已进入 Stable。它们提供了一种检查正则表达式是否在 String 或 CharSequence 的特定位置精确匹配的方法。
matchesAt() 检查是否匹配并返回布尔结果:
| |
matchAt() 如果找到匹配就返回该匹配,否则返回 null:
| |
我们欢迎你在这个 YouTrack 议题中提供反馈。
扩展对以往语言和 API 版本的支持
为了支持库作者开发可在大量以往 Kotlin 版本中使用的库,并应对 Kotlin 主版本发布频率的增加,我们扩展了对以往语言和 API 版本的支持。
在 Kotlin 1.7.0 中,我们支持三个以往的语言和 API 版本,而不是两个。这意味着 Kotlin 1.7.0 支持面向低至 1.4.0 的 Kotlin 版本的库开发。有关向后兼容性的更多信息,请参见兼容性选项。
通过反射访问注解
最初在 1.6.0 中引入的 KAnnotatedElement.findAnnotations() 扩展函数现在已进入 Stable。这个反射函数返回元素上给定类型的所有注解,包括单独应用的和重复的注解。
| |
稳定的深度递归函数
深度递归函数自 Kotlin 1.4.0 起作为实验性特性提供,现在在 Kotlin 1.7.0 中已进入 Stable。使用 DeepRecursiveFunction,你可以定义一个把栈保存在堆上而不是使用实际调用栈的函数。这让你可以运行非常深的递归计算。要调用深度递归函数,请 invoke 它。
在这个示例中,使用深度递归函数递归计算二叉树的深度。尽管这个示例函数递归调用自身 100,000 次,也不会抛出 StackOverflowError:
| |
当代码中的递归深度超过 1000 次调用时,可以考虑使用深度递归函数。
默认时间源基于内联类的时间标记
Kotlin 1.7.0 通过把 TimeSource.Monotonic 返回的时间标记改为内联值类,提升了时间测量功能的性能。这意味着调用 markNow()、elapsedNow()、measureTime() 和 measureTimedValue() 之类的函数时,不会再为其 TimeMark 实例分配包装类。尤其是在测量热路径中的一段代码时,这有助于把测量带来的性能影响降到最低:
| |
注意: 只有当获取
TimeMark的时间源被静态地确定为TimeSource.Monotonic时,这一优化才可用。
Java Optional 的新实验性扩展函数
Kotlin 1.7.0 带来了新的便捷函数,简化了在 Java 中使用 Optional 类的工作。这些新函数可用于在 JVM 上解包和转换 optional 对象,有助于让 Java API 的使用更简洁。
getOrNull()、getOrDefault() 和 getOrElse() 扩展函数允许你在 Optional 存在值时获取该值,否则分别得到 null、默认值或由函数返回的值:
| |
toList()、toSet() 和 asSequence() 扩展函数把存在值的 Optional 转换为列表、集合或序列,否则返回空集合。toCollection() 扩展函数把 Optional 的值追加到已有的目标集合中:
| |
这些扩展函数在 Kotlin 1.7.0 中作为实验性特性引入。你可以在这个 KEEP 中进一步了解 Optional 扩展。一如既往,我们欢迎你在 Kotlin 问题跟踪器中提供反馈。
JS 和 Native 中对命名捕获组的支持
从 Kotlin 1.7.0 开始,命名捕获组不仅在 JVM 上受支持,在 JS 和 Native 平台上同样受支持。
要给捕获组命名,请在正则表达式中使用 (?<name>group) 语法。要获取某个组匹配的文本,请调用新引入的 MatchGroupCollection.get() 函数并传入组名。
按名称获取匹配的组值
考虑这个匹配城市坐标的示例。要获取正则表达式匹配到的组的集合,请使用 groups。比较通过编号(索引)和通过名称并借助 value 获取组内容:
| |
命名反向引用
现在你也可以在反向引用组时使用组名。反向引用匹配之前由某个捕获组匹配到的相同文本。为此,请在正则表达式中使用 \k<name> 语法:
| |
替换表达式中的命名组
命名组引用可以与替换表达式一起使用。请考虑 replace() 函数(用替换表达式替换输入中指定正则表达式的所有匹配项)和 replaceFirst() 函数(只替换第一个匹配项)。
替换字符串中出现的 ${name} 会被替换为与指定名称的捕获组对应的子序列。你可以比较通过名称和索引引用组的替换结果:
| |
Gradle
此版本引入了新的构建报告、对 Gradle 插件变体的支持、kapt 中的新统计信息,以及更多内容:
- 增量编译的新方式
- 用于跟踪编译器性能的新构建报告
- 最低支持的 Gradle 和 Android Gradle 插件版本的变更
- 支持 Gradle 插件变体
- Kotlin Gradle 插件 API 的更新
- 可通过 plugins API 使用 sam-with-receiver 插件
- 编译任务的变更
- kapt 中每个注解处理器生成文件的新统计信息
- 弃用 kotlin.compiler.execution.strategy 系统属性
- 移除已弃用的选项、方法和插件
增量编译的新方式
警告: 增量编译的新方式是实验性的。它随时可能被放弃或更改。需要选择启用(详见下文)。我们鼓励你仅将其用于评估目的,并欢迎你在 YouTrack 中提供反馈。
在 Kotlin 1.7.0 中,我们重做了针对跨模块变更的增量编译。现在增量编译也支持依赖的非 Kotlin 模块中的变更,并且与 Gradle 构建缓存兼容。对编译规避(compilation avoidance)的支持也得到了改进。
如果你使用构建缓存或经常在非 Kotlin 的 Gradle 模块中进行更改,我们预计你会看到新方式最显著的好处。我们在 kotlin-gradle-plugin 模块上对 Kotlin 项目的测试显示,缓存命中后的变更改进超过 80%。
要试用这种新方式,请在 gradle.properties 中设置以下选项:
kotlin.incremental.useClasspathSnapshot=true
注意: 增量编译的新方式目前仅适用于 Gradle 构建系统中的 JVM 后端。
请在这篇博客文章中了解增量编译新方式的底层实现。
我们计划稳定这项技术,并增加对其他后端(例如 JS)和构建系统的支持。如果你在这种编译方案中遇到任何问题或异常行为,欢迎在 YouTrack 中报告。谢谢!
Kotlin 团队非常感谢 Ivan Gavrilovic、Hung Nguyen、Cédric Champeau 以及其他外部贡献者的帮助。
Kotlin 编译器任务的构建报告
警告: Kotlin 构建报告是实验性的。它们随时可能被放弃或更改。需要选择启用(详见下文)。请仅将它们用于评估目的。我们欢迎你在 YouTrack 中提供反馈。
Kotlin 1.7.0 引入了有助于跟踪编译器性能的构建报告。报告包含各个编译阶段的耗时,以及编译无法增量化进行的原因。
当你想调查编译器任务相关的问题时,构建报告会很有用,例如:
- 当 Gradle 构建耗时过长,而你想了解性能不佳的根本原因时。
- 当同一项目的编译时间不稳定,有时只需几秒,有时却需要几分钟时。
要启用构建报告,请在 gradle.properties 中声明构建报告输出的保存位置:
kotlin.build.report.output=file
以下值(及其组合)可用:
file把构建报告保存到本地文件。build_scan把构建报告保存到构建扫描的custom values部分。
Gradle Enterprise 插件会限制自定义值的数量和长度。在大型项目中,某些值可能会 丢失。
http通过 HTTP(S) 提交构建报告。POST 方法以 JSON 格式发送指标。数据可能随版本变化。你可以在 Kotlin 仓库中查看当前发送数据的版本。
分析耗时较长的编译的构建报告,可以帮助你解决两种常见情况:
- 构建不是增量的。分析原因并修复根本问题。
- 构建是增量的,但耗时过长。尝试重新组织源文件——拆分大文件、把不同的类保存到不同文件中、重构过大的类、把顶层函数声明到不同文件中等等。
请在这篇博客文章中进一步了解新的构建报告。
欢迎你在自己的基础设施中试用构建报告。如果你有任何反馈、遇到任何问题或想提出改进建议,请随时在我们的问题跟踪器中报告。谢谢!
提升最低支持版本
从 Kotlin 1.7.0 开始,最低支持的 Gradle 版本是 6.7.1。我们不得不提升该版本以支持 Gradle 插件变体和新的 Gradle API。得益于 Gradle 插件变体特性,将来我们不必那么频繁地提升最低支持版本。
此外,最低支持的 Android Gradle 插件版本现在是 3.6.4。
支持 Gradle 插件变体
Gradle 7.0 为 Gradle 插件作者引入了一项新特性——带变体的插件。该特性让添加对新 Gradle 特性的支持,同时保持对 7.1 以下 Gradle 版本的兼容性变得更容易。进一步了解 Gradle 中的变体选择。
借助 Gradle 插件变体,我们可以为不同的 Gradle 版本提供不同的 Kotlin Gradle 插件变体。目标是在 main 变体中支持基础 Kotlin 编译,该变体对应最旧的受支持 Gradle 版本。每个变体都会针对相应发布版本中的 Gradle 特性提供实现。最新的变体将支持最广泛的 Gradle 特性集。通过这种方式,我们可以以有限的功能扩展对旧版本 Gradle 的支持。
目前 Kotlin Gradle 插件只有两个变体:
main用于 Gradle 6.7.1–6.9.3 版本gradle70用于 Gradle 7.0 及更高版本
在未来的 Kotlin 版本中,我们可能会添加更多变体。
要查看你的构建使用哪个变体,请启用 --info 日志级别,并在输出中查找以 Using Kotlin Gradle plugin 开头的字符串,例如 Using Kotlin Gradle plugin main variant。
注意: 以下是一些已知的 Gradle 变体选择问题的变通方案:* pluginManagement 中的 ResolutionStrategy 对多变的插件无效 * 当插件作为
buildSrc的公共依赖添加时,插件变体会被忽略
请在这个 YouTrack 议题中留下你的反馈。
Kotlin Gradle 插件 API 的更新
Kotlin Gradle 插件 API 制品获得了若干改进:
- Kotlin/JVM 和 Kotlin/kapt 任务有了新的接口,其输入可由用户配置。
- 有了新的
KotlinBasePlugin接口,所有 Kotlin 插件都继承自它。当你希望在任何 Kotlin Gradle 插件(JVM、JS、Multiplatform、Native 及其他平台)被应用时触发某些配置操作,可以使用该接口:
| |
你可以在这个 YouTrack 议题中留下关于 KotlinBasePlugin 的反馈。
- 我们已经为 Android Gradle 插件在其内部配置 Kotlin 编译打下了基础,这意味着你不再需要把 Kotlin Android Gradle 插件添加到构建中。请关注 Android Gradle 插件发布公告以了解新增的支持并试用!
可通过 plugins API 使用 sam-with-receiver 插件
sam-with-receiver 编译器插件现在可以通过 Gradle plugins DSL 使用:
| |
编译任务的变更
编译任务在此版本中经历了许多变更:
- Kotlin 编译任务不再继承 Gradle 的
AbstractCompile任务。它们只继承DefaultTask。 AbstractCompile任务有sourceCompatibility和targetCompatibility输入。由于不再继承AbstractCompile任务,这些输入在 Kotlin 用户的脚本中不再可用。SourceTask.stableSources输入不再可用,你应该使用sources输入。setSource(...)方法仍然可用。- 所有编译任务现在都使用
libraries输入来指定编译所需的库列表。KotlinCompile任务仍有已弃用的 Kotlin 属性classpath,它将在未来的版本中被移除。 - 编译任务仍然实现
PatternFilterable接口,允许过滤 Kotlin 源文件。sourceFilesExtensions输入已被移除,改用PatternFilterable的方法。 - 已弃用的
Gradle destinationDir: File输出被替换为destinationDirectory: DirectoryProperty输出。 - Kotlin/Native 的
AbstractNativeCompile任务现在继承AbstractKotlinCompileTool基类。这是把 Kotlin/Native 构建工具集成到所有其他工具中的第一步。
请在这个 YouTrack 议题中留下你的反馈。
kapt 中每个注解处理器生成文件的统计信息
kotlin-kapt Gradle 插件已经可以报告每个处理器的性能统计信息。从 Kotlin 1.7.0 开始,它还可以报告每个注解处理器生成文件数量的统计信息。
这对于跟踪构建中是否存在未使用的注解处理器很有用。你可以使用生成的报告找出触发不必要注解处理器的模块,并更新这些模块以避免这种情况。
通过两步启用该统计信息:
- 在
build.gradle.kts中把showProcessorStats标志设置为true:
| |
- 在
gradle.properties中把kapt.verboseGradle 属性设置为true:
kapt.verbose=true
注意: 你也可以通过命令行选项
verbose启用详细输出。
统计信息会以 info 级别出现在日志中。你会看到 Annotation processor stats: 行,后面是每个注解处理器执行时间的统计信息。在这些行之后,会有 Generated files report: 行,后面是每个注解处理器生成文件数量的统计信息。例如:
| |
请在这个 YouTrack 议题中留下你的反馈。
弃用 kotlin.compiler.execution.strategy 系统属性
Kotlin 1.6.20 引入了用于定义 Kotlin 编译器执行策略的新属性。在 Kotlin 1.7.0 中,旧系统属性 kotlin.compiler.execution.strategy 的弃用周期已经开始,建议改用新属性。
使用 kotlin.compiler.execution.strategy 系统属性时你会收到警告。该属性将在未来的版本中删除。要保留旧行为,请用同名的 Gradle 属性替换该系统属性。例如,你可以在 gradle.properties 中这样做:
kotlin.compiler.execution.strategy=out-of-process
你也可以使用编译任务属性 compilerExecutionStrategy。请在编译器执行策略页面中了解更多。
移除已弃用的选项、方法和插件
移除 useExperimentalAnnotation 方法
在 Kotlin 1.7.0 中,我们完成了 useExperimentalAnnotation Gradle 方法的弃用周期。请改用 optIn() 来在模块中选择启用某个 API。
例如,如果你的 Gradle 模块是多平台的:
| |
请在 Kotlin 中进一步了解选择启用要求。
移除已弃用的编译器选项
我们完成了若干编译器选项的弃用周期:
kotlinOptions.jdkHome编译器选项在 1.5.30 中被弃用,并在当前版本中被移除。现在 Gradle 构建如果包含该选项就会失败。我们鼓励你使用自 Kotlin 1.5.30 起就受支持的 Java 工具链。- 已弃用的
noStdlib编译器选项也已被移除。Gradle 插件使用kotlin.stdlib.default.dependency=true属性来控制是否包含 Kotlin 标准库。
注意: 编译器参数
-jdkHome和-no-stdlib仍然可用。
移除已弃用的插件
在 Kotlin 1.4.0 中,kotlin2js 和 kotlin-dce-plugin 插件被弃用,它们已在此版本中被移除。请使用新的 org.jetbrains.kotlin.js 插件代替 kotlin2js。只要正确配置 Kotlin/JS Gradle 插件,死代码消除(DCE)就会生效。
在 Kotlin 1.6.0 中,我们把 KotlinGradleSubplugin 类的弃用级别改为 ERROR。开发者曾用这个类编写编译器插件。在此版本中,该类已被移除。请改用 KotlinCompilerPluginSupportPlugin 类。
提示: 最佳实践是在整个项目中使用 1.7.0 及更高版本的 Kotlin 插件。
移除已弃用的协程 DSL 选项和属性
我们移除了已弃用的 kotlin.experimental.coroutines Gradle DSL 选项以及在 gradle.properties 中使用的 kotlin.coroutines 属性。现在你只需使用_挂起函数_,或者向构建脚本添加 kotlinx.coroutines 依赖。
请在协程指南中进一步了解协程。
移除工具链扩展方法中的类型转换
在 Kotlin 1.7.0 之前,使用 Kotlin DSL 配置 Gradle 工具链时,你必须做类型转换到 JavaToolchainSpec 类:
| |
现在你可以省略 (this as JavaToolchainSpec) 部分:
| |
迁移到 Kotlin 1.7.0
安装 Kotlin 1.7.0
IntelliJ IDEA 2022.1 和 Android Studio Chipmunk (212) 会自动建议把 Kotlin 插件更新到 1.7.0。
注意: 对于 IntelliJ IDEA 2022.2 以及 Android Studio Dolphin (213) 或 Android Studio Electric Eel (221),Kotlin 插件 1.7.0 将随即将发布的 IntelliJ IDEA 和 Android Studio 更新一起提供。
新的命令行编译器可在 GitHub 发布页面下载。
使用 Kotlin 1.7.0 迁移现有项目或创建新项目
要把现有项目迁移到 Kotlin 1.7.0,请将 Kotlin 版本改为
1.7.0并重新导入你的 Gradle 或 Maven 项目。了解如何更新到 Kotlin 1.7.0。要使用 Kotlin 1.7.0 开始一个新项目,请更新 Kotlin 插件,然后从 File | New | Project 运行项目向导。
Kotlin 1.7.0 兼容性指南
Kotlin 1.7.0 是一个特性版本,因此可能带来与为早期语言版本编写的代码不兼容的变更。请在 Kotlin 1.7.0 兼容性指南中找到这些变更的详细列表。