前言
Kotlin
已经发布了1.7.0
版本,该版本带来了新Kotlin/JVM K2
编译器的Alpha
版本,稳定了语言特性,并为JVM
、JS
和 Native
平台带来了性能改进。
主要更新列表
以下是此版本的主要更新列表:
-
新的 Kotlin К2 编译器目前处于 Alpha 阶段,提供了显着的性能改进,但仅适用于
JVM
,包括kapt
在内的所有编译器插件都不能使用它。 -
Gradle 中增量编译的一种新方法。增量编译现在也支持在依赖的非
Kotlin
模块中进行的更改,并且与Gradle
兼容。 -
新增用于 args 类型的下划线运算符。在指定其他类型时,可以使用它自动推断参数类型。
-
允许通过委托实现内联类的内联值。可以创建在大多数情况下不分配内存的轻量级包装器。
详细介绍
Alpha 版中 用于 JVM 的 Kotlin K2 编译器
这个版本引入了新的Kotlin K2
编译器的 Alpha
版本。新编译器旨在加快新语言功能的开发,统一Kotlin
支持的所有平台,带来性能改进,并为编译器扩展提供API
。
目前已经发布的一些有关新编译器和其优点的详细说明见下列内容:
目前,对于新的K2
编译器的 Alpha
版本。主要关注与性能改进,并仅适用于JVM
项目。目前不支持 Kotlin/JS
、Kotlin/Native
或其他多平台项目,包括kapt在内的任何编译器插件都不能使用它。
在项目基准测试中,新编译器的出色表现:
Project | Current Kotlin compiler performance | New K2 Kotlin compiler performance | Performance boost |
---|---|---|---|
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 性能数字代表编译器每秒处理的数千行代码的数量
你也可以检验在JVM
项目中性能提升,并将其与旧编译器的结果相比较。
如果要启用Kotlin K2
编译器,请使用以下编译器选项:
-Xuse-k2
此外,K2
编译器还包括了许多错误修复。注意:即使在列表中状态为open
的issue
问题,实际也已经在K2
编译器中修复。
下一个Kotlin
版本将提高K2
编译器的稳定性并提供更多功能。
语言方面
Kotlin 1.7.0
引入了对委托实现的支持以及用于类型参数的新下划线运算符。还稳定了以前版本中作为预览引入的几个语言功特性:
允许通过委托实现内联类的内联值
在1.7.0
之前,如果要为值或类实例创建轻量级包装器,需要手动实现所有接口方法。委托实现解决了这个问题,此限制已被删除,现在你可以创建在大多数情况下不分配内存的轻量级包装器。
interface Bar {
fun foo() = "foo"
}
@JvmInline
value class BarWrapper(val bar: Bar): Bar by bar
fun main() {
val bw = BarWrapper(object: Bar {})
println(bw.foo())
}
类型参数的下划线运算符
Kotlin 1.7.0
为类型参数引入了下划线运算符_
,当指定其他类型时,可以使用它来自动推断类型参数:
abstract class SomeClass<T> {
abstract fun execute(): T
}
class SomeImplementation : SomeClass<String>() {
override fun execute(): String = "Test"
}
class OtherImplementation : SomeClass<Int>() {
override fun execute(): Int = 42
}
object Runner {
inline fun <reified S: SomeClass<T>, T> run(): T {
return S::class.java.getDeclaredConstructor().newInstance().execute()
}
}
fun main() {
// T is inferred as String because SomeImplementation derives from SomeClass<String>
val s = Runner.run<SomeImplementation, _>()
assert(s == "Test")
// T is inferred as Int because OtherImplementation derives from SomeClass<Int>
val n = Runner.run<OtherImplementation, _>()
assert(n == 42)
}
现在可以在变量列表中的任何位置使用下划线运算符来推断类型参数。
构造器推断
构建器推断是一种特殊的类型推断,在调用通用构建器函数时很有用。在其lambda
参数中使用有关其他调用的类型信息时,它帮助编译器推断调用的类型参数。
从1.7.0
开始,如果没有指定-Xenable-builder-inference
编译器选项(在1.6.0
中引入),常规类型推断无法获得有关类型的足够信息,则会自动激活构建器推断。
opt-in requirements
opt-in requirements
现在不再需要额外的编译器配置。
在1.7.0
之前,选择加入功能本身需要参数 opt-in=kotlin.RequiresOptIn
以避免出现警告。m目前已经不再需要这个,但仍然可以使用编译器参数-opt-in
以模块方式选择其他注释
绝对不可为空的类型
在Kotlin 1.7.0
中,绝对不可为空的类型已被提升为稳定支持。在扩展通用Java
类和接口时,它们提供了更好的互操作性。
你可以使用新语法 T & Any
将泛型类型参数标记为绝对不可为空
fun <T> elvisLike(x: T, y: T & Any): T & Any = x ?: y
fun main() {
// OK
elvisLike<String>("", "").length
// Error: 'null' cannot be a value of a non-null type
elvisLike<String>("", null).length
// OK
elvisLike<String?>(null, "").length
// Error: 'null' cannot be a value of a non-null type
elvisLike<String?>(null, null).length
}
更多有关 绝对不可为空的类型的信息.
Kotlin/JVM
此版本为Kotlin/JVM
编译器带来了性能改进和一个新的编译器选项。此外,对功能接口构造函数的可调用引用已变为稳定版。请注意,从1.7.0
开始,Kotlin/JVM
编译的默认目标版本现在是1.8
。
编译器性能优化
Kotlin 1.7.0
引入了Kotlin/JVM
编译器的性能改进。根据Kotlin
团队的基准测试,与Kotlin 1.6.0
相比,编译时间平均减少了10%
。
新的编译器选项 -Xjdk-release
Kotlin 1.7.0
提供了一个新的编译器选项 -Xjdk-release
。此选项类似于javac
命令行中的--release
选项。-Xjdk-release
选项可以控制目标的字节码版本,并将类路径中JDK
的API
限制为指定的Java
版本。例如,kotlinc -Xjdk-release=1.8
, 将不允许引用java.lang.Module
,即使依赖项中的JDK
是9
或更高版本。
此选项仅适用于 OpenJDK 发行版。
稳定支持对功能接口构造函数的引用调用
稳定支持对功能接口构造函数的引用调用。你可以了解如何从具有构造函数的接口迁移到使用可调用引用的函数式接口。
移除了 JVM 目标版本 1.6
Kotlin/JVM
编译的默认目标版本已经变为1.8
。 1.6
已被删除。
请升级到JVM 1.8
或更高版本。了解如何更新JVM
目标版本。可以参考:
Kotlin/Native
Kotlin/JS
正在对JS IR
编译器后端进行进一步改进以及其他可以使您的开发体验更好的更新:
新 IR 后端的性能改进
此版本有一些重大更新,可以改善开发体验:
-
Kotlin/JS
的增量编译性能得到了显着提升。构建JS
项目所需的时间更少。在许多情况下,增量重建现在应该与legacy backend
大致相当。 -
Kotlin/JS
最终包需要更少的空间,与一些大型项目的legacy backend
相比,生产包大小减少了20%
。 -
接口的类型检查已经提高了几个数量级。
-
Kotlin
生成更高质量的JS
代码
使用 IR 时成员名称的缩小
Kotlin/JS IR
编译器现在使用其关于Kotlin
类和函数关系的内部信息来应用更有效的压缩,缩短函数、属性和类的名称。这会缩小生成的捆绑应用程序。
在生产模式下构建Kotlin/JS
应用程序时会自动应用这种类型的缩小,并且默认启用。要禁用成员名称缩小,可以使用-Xir-minimized-member-names
编译器标志:
kotlin {
js(IR) {
compilations.all {
compileKotlinTask.kotlinOptions.freeCompilerArgs += listOf("-Xir-minimized-member-names=false")
}
}
}
在 IR 后端通过 polyfill 支持旧版浏览器
Kotlin/JS
的IR
编译器后端现在包含与旧后端相同的polyfill
。允许使用新编译器编译的代码在旧浏览器(不支持Kotlin
标准库使用的ES2015
中的所有方法。)中运行。只有项目实际使用的那些polyfill
才会包含在最终的包中,这样可以最大限度地减少它们对包大小的潜在影响。
从 js 表达式动态加载 JavaScript 模块
使用JavaScript
模块时,大多数应用程序使用静态导入,其使用包含在JavaScript
的模块集成中。而Kotlin/JS
缺少在应用程序运行时动态加载JavaScript
模块的机制。
从Kotlin 1.7.0
开始,js
中支持来自JavaScript
的import
语句,允许在运行时动态地将包引入应用程序:
val myPackage = js("import('my-package')")
为 JavaScript 测试运行器指定环境变量
要调整Node.js
包解析或将外部信息传递给Node.js
测试,现在可以指定JavaScript
测试运行器使用的环境变量
定义环境变量,需要在构建脚本的testTask
内使用environment()
函数和键值对:
kotlin {
js {
nodejs {
testTask {
environment("key", "value")
}
}
}
}
标准库
在 Kotlin 1.7.0
中,标准库进行了一系列的改进。引入了新的特性,稳定了实验特性,并统一了对Native
、JS
和JVM
的命名捕获组的支持:
- min() 和 max() 集合函数返回不可为空
- 特定索引处的正则表达式匹配
- 对以前的语言和 API 版本的扩展支持
- 通过反射访问注释
- 稳定版的深度递归函数
- 基于默认时间源的内联类的时间标记
- Java Optionals 的新实验性扩展函数
- 支持 JS 和 Native 中的命名捕获组
min() 和 max() 集合函数返回不可为空
在Kotlin 1.4.0 中, min()
andmax()
集合函数被重命名为minOrNull()
和 maxOrNull()
。这些新名称更好地反映了它们的行为(如果接收者集合为空,则返回 null
)。它还有助于使函数的行为与整个Kotlin
集合API
中使用的命名约定保持一致。
minBy()
, maxBy()
, minWith()
, 和 maxWith()
也是如此。在Kotlin 1.4.0
中都有它们的 OrNull() 同义词。此旧功能逐渐被弃用。
Kotlin 1.7.0
重新引入了原始函数名称,但返回类型不可为空。新的 min()
、max()
、minBy()
、maxBy()
、minWith()
和 maxWith()
函数现在严格返回集合元素或抛出异常。
fun main() {
val numbers = listOf<Int>()
println(numbers.maxOrNull()) // "null"
println(numbers.max()) // "Exception in... Collection is empty."
}
特定索引处的正则表达式匹配
1.5.30
中引入的 Regex.matchAt()
和 Regex.matchesAt()
函数现在已经成为稳定支持的。它们提供了一种方法来检查正则表达式是否在String
或CharSequence
中的特定位置完全匹配。
matchesAt()
检查匹配并返回布尔结果:
fun main() {
val releaseText = "Kotlin 1.7.0 is on its way!"
// regular expression: one digit, dot, one digit, dot, one or more digits
val versionRegex = "\\d[.]\\d[.]\\d+".toRegex()
println(versionRegex.matchesAt(releaseText, 0)) // "false"
println(versionRegex.matchesAt(releaseText, 7)) // "true"
}
matchAt()
如果找到匹配项,则返回匹配项,否则返回 null
:
fun main() {
val releaseText = "Kotlin 1.7.0 is on its way!"
val versionRegex = "\\d[.]\\d[.]\\d+".toRegex()
println(versionRegex.matchAt(releaseText, 0)) // "null"
println(versionRegex.matchAt(releaseText, 7)?.value) // "1.7.0"
}
对以前的语言和 API 版本的扩展支持
为了支持库作者开发的库可以在各种先前的Kotlin
版本中使用,并解决主要Kotlin
版本的频率增加,该版本扩展了对先前语言和API
版本的支持。
在Kotlin 1.7.0
中,支持向前三个的语言和API
版本,而不再是两个。这意味着Kotlin 1.7.0
支持针对 Kotlin
版本低至1.4.0
的库的开发。有关向后兼容性的更多信息,请参阅兼容模式。
通过反射访问注释
在1.6.0
中首次引入的扩展功能现在是 Stable。此反射函数返回元素上给定类型的所有注释,包括单独应用和重复的注释。KAnnotatedElement.findAnnotations()
@Repeatable
annotation class Tag(val name: String)
@Tag("First Tag")
@Tag("Second Tag")
fun taggedFunction() {
println("I'm a tagged function!")
}
fun main() {
val x = ::taggedFunction
val foo = x as KAnnotatedElement
println(foo.findAnnotations<Tag>())
// [@Tag(name=First Tag), @Tag(name=Second Tag)]
}
稳定版的深度递归函数
自Kotlin 1.4.0 以来,深度递归函数已作为实验性功能提供,现在它们在Kotlin 1.7.0 中是
Stable 使用 DeepRecursiveFunction
,可以定义一个将其堆栈保留在堆上的函数,而不是使用实际的调用堆栈。这允许运行非常深的递归计算。要调用一个深度递归函数,可以使用invoke
。
在下列示例中,使用深度递归函数递归计算二叉树的深度。即使这个示例函数递归调用自身 100,000
次。也不会抛出StackOverflowError
异常。
class Tree(val left: Tree?, val right: Tree?)
val calculateDepth = DeepRecursiveFunction<Tree?, Int> { t ->
if (t == null) 0 else maxOf(
callRecursive(t.left),
callRecursive(t.right)
) + 1
}
fun main() {
// Generate a tree with a depth of 100_000
val deepTree = generateSequence(Tree(null, null)) { prev ->
Tree(prev, null)
}.take(100_000).last()
println(calculateDepth(deepTree)) // 100000
}
考虑在递归深度超过 1000 次调用的代码中使用深度递归函数
基于默认时间源的内联类的时间标记
Kotlin 1.7.0
通过将TimeSource.Monotonic
返回的时间标记更改为内联值类来提高时间测量功能的性能。
这意味着调用诸如markNow()
、elapsedNow()
、measureTime()
和 measureTimedValue()
之类的函数不会为其TimeMark
实例分配包装类。
尤其是在测量属于热路径的一段代码时,这有助于最大限度地减少测量对性能的影响:
@OptIn(ExperimentalTime::class)
fun main() {
val mark = TimeSource.Monotonic.markNow() // Returned `TimeMark` is inline class
val elapsedDuration = mark.elapsedNow()
}
仅当从中获取 TimeMark 的时间源静态已知为 TimeSource.Monotonic 时,此优化才可用。
Java Optionals 的新实验性扩展函数
Kotlin 1.7.0
带有新的便利函数,可简化在Java
中使用Optional
类的工作。这些新函数可用于解包和转换 JVM
上的可选对象,并有助于更简洁地使用Java API
。
getOrNull()
、getOrDefault()
和 getOrElse()
扩展函数允许获取Optional
的值(如果存在)。否则,将分别获得默认值、null
或函数返回的值。
val presentOptional = Optional.of("I'm here!")
println(presentOptional.getOrNull())
// "I'm here!"
val absentOptional = Optional.empty<String>()
println(absentOptional.getOrNull())
// null
println(absentOptional.getOrDefault("Nobody here!"))
// "Nobody here!"
println(absentOptional.getOrElse {
println("Optional was absent!")
"Default value!"
})
// "Optional was absent!"
// "Default value!"
toList()
、toSet()
和 asSequence()
扩展函数将当前 Optional
的值转换为列表、集合或序列,否则返回空集合。toCollection()
扩展函数将Optional
值附加到已经存在的目标集合。
val presentOptional = Optional.of("I'm here!")
val absentOptional = Optional.empty<String>()
println(presentOptional.toList() + "," + absentOptional.toList())
// ["I'm here!"], []
println(presentOptional.toSet() + "," + absentOptional.toSet())
// ["I'm here!"], []
val myCollection = mutableListOf<String>()
absentOptional.toCollection(myCollection)
println(myCollection)
// []
presentOptional.toCollection(myCollection)
println(myCollection)
// ["I'm here!"]
val list = listOf(presentOptional, absentOptional).flatMap { it.asSequence() }
println(list)
// ["I'm here!"]
这些扩展函数在Kotlin 1.7.0
中作为实验性引入。了解有关可选扩展的更多信息,请 移步
支持 JS 和 Native 中的命名捕获组
从Kotlin 1.7.0
开始,命名捕获组不仅在JVM
上支持,在JS
和Native
平台上也将支持。
要为捕获组命名,请在正则表达式中使用 (?<name>group)
语法。要获取组匹配的文本,请调用新引入的 MatchGroupCollection.get()
函数并传递组名称。
按名称检索匹配的组值
参考下面这个匹配城市坐标的例子。要获取与正则表达式匹配的组的集合,请使用组。比较按组的编号(索引)和使用值的名称检索组的内容:
fun main() {
val regex = "\\b(?<city>[A-Za-z\\s]+),\\s(?<state>[A-Z]{2}):\\s(?<areaCode>[0-9]{3})\\b".toRegex()
val input = "Coordinates: Austin, TX: 123"
val match = regex.find(input)!!
println(match.groups["city"]?.value) // "Austin" — by name
println(match.groups[2]?.value) // "TX" — by number
}
命名反向引用
现在还可以在反向引用组时使用组名。反向引用匹配先前由捕获组匹配的相同文本。为此,请在正则表达式中使用 \k<name>
语法:
fun backRef() {
val regex = "(?<title>\\w+), yes \\k<title>".toRegex()
val match = regex.find("Do you copy? Sir, yes Sir!")!!
println(match.value) // "Sir, yes Sir"
println(match.groups["title"]?.value) // "Sir"
}
替换表达式中的命名组
命名组引用可以与替换表达式一起使用。考虑用替换表达式替换输入中所有出现的指定正则表达式的replace()
函数,以及仅交换第一个匹配项的replaceFirst()
函数。
替换字符串中出现的${name}
将替换为与具有指定名称的捕获组对应的子序列。可以按名称和索引比较组引用中的替换:
fun dateReplace() {
val dateRegex = Regex("(?<dd>\\d{2})-(?<mm>\\d{2})-(?<yyyy>\\d{4})")
val input = "Date of birth: 27-04-2022"
println(dateRegex.replace(input, "\${yyyy}-\${mm}-\${dd}")) // "Date of birth: 2022-04-27" — by name
println(dateRegex.replace(input, "\$3-\$2-\$1")) // "Date of birth: 2022-04-27" — by number
}
Gradle
此版本引入了新的构建报告、对Gradle
插件变体的支持、kapt
中的新统计信息等等:
- 增量编译的新方法
- 用于跟踪编译器性能的新构建报告
- 对 Gradle 和 Android Gradle 插件的最低支持版本的更改
- 支持 Gradle 插件变体
- Kotlin Gradle 插件 API 中的更新
- 通过插件 API 提供 sam-with-receiver 插件
- 编译任务的变化
- 为
kapt
中的每个注释处理器生成生成文件统计 - 弃用 kotlin.compiler.execution.strategy 系统属性
- 删除不推荐使用的选项、方法和插件
增量编译的新方法
增量编译的新方法是实验性的。它可能随时被删除或更改。
在Kotlin 1.7.0
中,Kotlin
团队为跨模块更改重新设计了增量编译。现在,在依赖的非Kotlin
模块中所做的更改也支持增量编译,并且它与Gradle
构建缓存兼容 对编译避免的支持也得到了改进。
如果你构建缓存或经常在非otlin Gradle
块中进行更改,你将会看到新方法所带来的最大好处。在kotlin-gradle-plugin
模块上对Kotlin
项目的测试表明,缓存命中后的更改提高了80%
以上。
要尝试这种新方法,请在gradle.properties
中设置以下选项
kotlin.incremental.useClasspathSnapshot=true
增量编译的新方法目前仅适用于 Gradle 构建系统中的 JVM 后端。
Kotlin
团队的计划是稳定这项技术并增加对其他后端(例如 JS)和构建系统的支持。
为 Kotlin 编译器任务构建报告
Kotlin 构建报告是实验性的。它们可能随时被删除或更改。
Kotlin 1.7.0
引入了帮助跟踪编译器性能的构建报告。报告包含不同编译阶段的持续时间,以及编译不能增量的原因。
当想要调查编译器任务的问题时,构建报告将会以下时机帮助你,例如:
- 当
Gradle
构建花费太多时间并且你想了解性能不佳的根本原因时。 - 当同一个项目的编译时间不同时,有时需要几秒钟,有时需要几分钟。
要启用构建报告,请在gradle.properties
中声明构建报告输出的保存位置:
kotlin.build.report.output=file
以下值(及其组合)可用:
file
将构建报告保存在本地文件中build_scan
将构建报告保存在[build scan](https://scans.gradle.com/).
的custom values
。http
使用HTTP(S)
发布构建报告。POST
方法以JSON
格式发送指标。数据可能会因版本而异。可以在Kotlin
存储库中查看已发送数据的当前版本。
分析长时间运行编译的构建报告可以帮助解决两种常见情况:
构建不是增量的
。分析原因,解决根本问题。构建是增量的,但花费了太多时间
。尝试重新组织源文件——拆分大文件,将单独的类保存在不同的文件中,重构大类,在不同的文件中声明顶级函数,等等
修改最低支持版本
从Kotlin 1.7.0
开始,支持的最低Gradle
版本为 6.7.1
。我们必须提高版本以支持Gradle
插件变体和新的 Gradle API
将来,由于Gradle
插件变体功能,Kotlin
团队认为不应该经常提高支持的最低版本。
支持 Gradle 插件变体
Gradle 7.0
为 Gradle
插件作者引入了一项新功能——带有变体的插件
。此功能可以更轻松地添加对新 Gradle
功能的支持,同时保持对低于7.1
的 Gradle
版本的兼容性。
使用 Gradle
插件变体,我们可以为不同的Gradle
版本提供不同的 Kotlin Gradle
插件变体。目标是在主要变体中支持基础Kotlin
编译,这对应于Gradle
的最旧支持版本。每个变体都将具有相应版本中Gradle
功能的
实现。最新的变体将支持最广泛的Gradle
功能集。通过这种方法,我们可以扩展对功能有限的旧Gradle
版本的支持。
目前,Kotlin Gradle
插件只有两种变体:
main
对于Gradle
版本6.7.1 – 6.9.2
gradle70
对于Gradle 7.0
及更高版本
要检查你的构建使用的哪个变体,启用--info
日志级别并在输出中查找以Using Kotlin Gradle plugin
开头的字符串,例如,Using Kotlin Gradle plugin main variant
。
以下是 Gradle 中变体选择的一些已知问题的解决方法:
pluginManagement 中的 ResolutionStrategy 不适用于具有多变量的插件
当插件作为 buildSrc 通用依赖项添加时,插件变体被忽略
Kotlin Gradle 插件 API 中的更新
该版本Kotlin Gradle
插件API
工件已获得多项改进:
Kotlin/JVM
和Kotlin/kapt
任务具有用户可配置输入的新接口- 所有
Kotlin
插件都继承自一个新的KotlinBasePlugin
接口。当想在应用任何Kotlin Gradle
插件(JVM
、JS
、Multiplatform
、Native
和其他平台)时触发一些配置操作时,请使用此接口:
project.plugins.withType<org.jetbrains.kotlin.gradle.plugin.KotlinBasePlugin>() {
// Configure your action here
}
Kotlin
团队已经为Android Gradle
插件在其内部配置Kotlin
编译奠定了基础,这意味着无需将Kotlin Android Gradle
插件添加到我们的构建中。
可通过插件 API 获得 sam-with-receiver 插件
sam-with-receiver
编译器插件现在可以通过 Gradle
插件 DSL
获得:
plugins {
id("org.jetbrains.kotlin.plugin.sam.with.receiver") version "$kotlin_version"
}
编译任务的变化
编译任务在此版本中进行了很多更改:
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
构建工具集成到所有其他工具的第一步
为kapt
中的每个注释处理器生成生成文件统计
kotlin-kapt Gradle
插件已经报告了每个处理器的性能统计信息。从Kotlin 1.7.0
开始,它还可以报告每个注释处理器生成的文件数量的统计信息。
这对于跟踪是否有未使用的注释处理器作为构建的一部分很有用。现在你可以使用生成的报告来查找触发不必要注释处理器的模块并更新模块以防止这种情况发生。
分两步以启用统计信息:
- 在
build.gradle.kts
中将showProcessorStats
标志设置为true
:kapt { showProcessorStats = true }
- 在
gradle.properties
中将kapt.verbose Gradle
属性设置为true
:kapt.verbose=true
还可以通过命令行选项 verbose 启用详细输出。
他的统计信息将出现在具有info
级别的日志中。你将看到Annotation processor stats:
。行后面是每个注释处理器的执行时间的统计信息。在这些行之后,将出现Generated files report:
行,然后是每个注释处理器生成的文件数量的统计信息。例如:
[INFO] Annotation processor stats:
[INFO] org.mapstruct.ap.MappingProcessor: total: 290 ms, init: 1 ms, 3 round(s): 289 ms, 0 ms, 0 ms
[INFO] Generated files report:
[INFO] org.mapstruct.ap.MappingProcessor: total sources: 2, sources per round: 2, 0, 0
弃用 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
。请在 Gradle 页面上 了解更多信息
删除不推荐使用的选项、方法和插件
移除 useExperimentalAnnotation 方法
在 Kotlin 1.7.0
中,Kotlin
团队完成了useExperimentalAnnotation Gradle
方法的弃用周期。使用 optIn()
来选择在模块中使用 API
。
例如,如果你的 Gradle
模块是多平台的:
sourceSets {
all {
languageSettings.optIn("org.mylibrary.OptInAnnotation")
}
}
删除不推荐使用的编译器选项
已经完成了几个编译器选项的弃用周期:
kotlinOptions.jdkHome
编译器选项在1.5.30
中已弃用,并已在当前版本中删除。- 已弃用的
noStdlib
编译器选项也已删除。Gradle
插件使用kotlin.stdlib.default.dependency=true
属性来控制是否存在Kotlin
标准库。
编译器参数 -jdkHome 和 -no-stdlib 仍然可用
删除不推荐使用的插件
在 Kotlin 1.4.0
中,kotlin2js
和 kotlin-dce-plugin
插件已被弃用,并且在此版本中已被删除。使用新的 org.jetbrains.kotlin.js
插件代替 kotlin2js
。使用新的org.jetbrains.kotlin.js
插件。正确配置 Kotlin/JS Gradle 插件后
,Dead code elimination
(DCE) 即可工作。
在 Kotlin 1.6.0
中,KotlinGradleSubplugin
类的弃用级别更改为错误
。开发人员使用这个类来编写编译器插件。在此版本中,已删除此类。请改用 KotlinCompilerPluginSupportPlugin
类。
最佳实践是在整个项目中使用 1.7.0 及更高版本的 Kotlin 插件。
删除不推荐使用的协程 DSL 选项和属性
该版本删除了已弃用的 kotlin.experimental.coroutines Gradle DSL
选项和 gradle.properties
中使用的 kotlin.coroutines
属性。现在可以只使用 suspending functions 或将 kotlinx.coroutines
依赖项添加到构建脚本中。
删除工具链扩展方法中的类型转换
在 Kotlin 1.7.0
之前,在使用 Kotlin DSL
配置 Gradle
工具链时,必须将类型转换为 JavaToolchainSpec
类:
kotlin {
jvmToolchain {
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)
}
}
现在,可以省略这(this as JavaToolchainSpec
) 部分:
kotlin {
jvmToolchain {
languageVersion.set(JavaLanguageVersion.of(<MAJOR_JDK_VERSION>)
}
}
如何迁移到 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 Studios
更新一起提供。
新的命令行编译器可在 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 的兼容性指南 中查看更改的详细列表。