Kotlinv2.4.0

Kotlin 2.4.x 兼容性指南

_保持语言现代性舒适更新_是 Kotlin 语言设计的基本原则。前者指出应当移除阻碍语言演进的结构,后者则强调这种移除应当事先进行充分沟通,以使代码迁移尽可能顺畅。

虽然大多数语言变更已经通过其他渠道(如更新日志或编译器警告)发布,但本文档对这些变更进行了汇总,为从 Kotlin 2.3 迁移到 Kotlin 2.4 提供完整的参考。本文档还包含了与工具相关的变更信息。

基本术语

在本文档中,我们引入了几种兼容性:

  • 源码 (source):源码不兼容的变更会导致以前可以正常编译(没有错误或警告)的代码不再能够编译
  • 二进制 (binary):如果交换两个二进制构件不会导致加载或链接错误,则称它们为二进制兼容
  • 行为 (behavioral):如果在应用变更前后,同一个程序表现出不同的行为,则称该变更为行为不兼容

请记住,这些定义仅适用于纯 Kotlin。从其他语言(例如 Java)的角度来看 Kotlin 代码的兼容性不在本文档的讨论范围内。

语言

停止支持 -language-version=1.9 和 K1 编译器

问题KT-80590

组件:编译器

不兼容变更类型:源码

简要总结:从 Kotlin 2.4 开始,编译器不再支持 -language-version=1.9。因此,K1 编译器也不再受支持。

弃用周期

  • 2.2.0:使用 1.9 版本的 -language-version 时报告警告
  • 2.4.0:将该警告提升为错误

禁止 Java 类型的灵活显式可空类型实参

问题KTLC-284

组件:核心语言

不兼容变更类型:源码

简要总结:以前,从 Kotlin 调用 Java API 时,编译器可能会将显式指定的可空类型实参视为灵活类型实参。Kotlin 2.4.0 不再对可空类型实参应用此行为,因此编译器现在会对可能破坏类型安全或在运行时失败的代码报告错误。

弃用周期

  • 2.2.0:对于被视为灵活类型的显式指定可空类型实参报告警告
  • 2.4.0:将该警告提升为错误

禁止对绝对不兼容的类型进行始终为假的 is 检查

问题KTLC-365

组件:核心语言

不兼容变更类型:源码

简要总结:编译器现在会阻止因检查类型绝对不兼容而导致始终为假的无意义 is 检查。这保持了与其他涉及不兼容类型操作的一致行为。

弃用周期

  • 2.0.0:对绝对不兼容类型的 is 检查报告警告
  • 2.4.0:将该警告提升为错误

禁止在内联函数中暴露具有较低可见性的类型和声明

问题KTLC-283

组件:核心语言

不兼容变更类型:源码

简要总结:编译器现在会阻止内联函数暴露可见性低于内联函数本身的类型和声明。

弃用周期

  • 2.3.0:对在内联函数中暴露具有较低可见性的类型和声明报告警告
  • 2.4.0:将该警告提升为错误

更改注解的默认使用点目标选择

问题KTLC-391

组件:核心语言

不兼容变更类型:二进制

简要总结:Kotlin 2.4.0 更新了将注解传播到形参、属性和字段的默认规则。这可能会影响重新编译后的注解处理、反射和二进制元数据。当您未指定使用点目标时,编译器现在会优先使用 paramproperty(如果适用),并且仅在 property 不适用时才使用 field

您可以显式指定使用点目标,例如使用 @param:Annotation 代替 @Annotation。要在整个项目中使用之前的默认规则,请在构建文件中添加 -Xannotation-default-target=first-only

弃用周期

  • 2.2.0:当新的默认规则改变所选的使用点目标时报告警告
  • 2.4.0:启用新的默认规则

禁止对不可访问类型的隐式引用

问题KTLC-384

组件:核心语言

不兼容变更类型:源码

简要总结:使用隐式引用间接依赖项中不可访问类型的声明现在会导致错误。

要进行迁移,请对声明该不可访问类型的模块添加显式依赖项,或者更新中间 API 以使其不再暴露该类型。

弃用周期

  • 2.3.0:对不可访问类型的隐式引用报告警告
  • 2.4.0:将该警告提升为错误

强制执行 Jakarta 为 null 性注解

问题KTLC-285

组件:核心语言

不兼容变更类型:源码

简要总结:对于使用 jakarta.annotation.Nullablejakarta.annotation.Nonnull 的 Java 声明,编译器现在会在 Kotlin 中强制执行声明的为 null 性。如果您将这些注解标记为可空的 Java 声明赋值给非空 Kotlin 类型,编译器会报告错误。

弃用周期

  • 2.2.0:对于带有 Jakarta 为 null 性注解的 Java 声明中的为 null 性不匹配报告警告
  • 2.4.0:将该警告提升为错误

报告可调用引用限定符中位置错误的类型实参

问题KTLC-388

组件:核心语言

不兼容变更类型:源码

简要总结:编译器现在会检查可调用引用的左侧,如果内部类在限定符的错误部分包含类型实参,则会报告警告。

要进行迁移,请更新引用,使每个类型实参属于声明它的类。例如,编写完整类型 Outer<Int>.Inner<String>::toString 而不是 Inner<String, Int>::toString

弃用周期

  • 2.4.0:当可调用引用左侧的类型实参属于限定符的另一部分时报告警告

对于具有可空上界的具体化类型形参的类文字报告错误

问题KTLC-370

组件:核心语言

不兼容变更类型:源码

简要总结:当您对类型源自具有可空上界的具体化类型形参的表达式使用 ::class 时,编译器现在会报告错误。如果您在此类表达式上使用 ::class,请先通过显式 null 检查或 !! 运算符使值变为非空。

弃用周期

  • 2.3.0:当对类型源自具有可空上界的具体化类型形参的表达式使用 ::class 时报告警告
  • 2.4.0:将该警告提升为错误

禁止在匿名对象声明之前进行初始化

问题KTLC-290

组件:核心语言

不兼容变更类型:源码

简要总结:如果在声明属性之前,在匿名对象的 init 块中初始化该属性,Kotlin 现在会报告错误。

弃用周期

  • 2.2.20:当匿名对象中的 init 块在属性声明之前初始化属性时报告警告
  • 2.4.0:将该警告提升为错误

对包含非抽象 Java 密封类的 when 表达式强制执行完备性

问题KTLC-366

组件:核心语言

不兼容变更类型:源码

简要总结:Kotlin 现在更严格地检查完备性。当您对非抽象 Java 密封类使用 when 表达式时,要求提供 else 分支或匹配密封类本身的分支。以前,即使 Java 密封类本身可以直接实例化,Kotlin 也可能将此类 when 表达式视为完备的。

弃用周期

  • 2.3.0:对包含非抽象 Java 密封类的非完备 when 表达式报告警告
  • 2.4.0:将该警告提升为错误

禁止在参数过多的 getValue()setValue() 函数上使用 operator 修饰符

问题KTLC-289

组件:核心语言

不兼容变更类型:源码

简要总结:当您使用 operator 修饰符标记 getValue()setValue() 函数时,编译器现在会检查它们是否具有所需数量的数值实参。getValue() 函数必须恰好有两个数值实参,而 setValue() 函数必须恰好有三个。要进行迁移,请移除 operator 修饰符或更改方法签名。

弃用周期

  • 2.2.20:对数值实参过多的 operator getValue()setValue() 函数报告警告
  • 2.4.0:将该警告提升为错误

禁止泛型调用中不一致的类型实参

问题KTLC-373

组件:核心语言

不兼容变更类型:源码

简要总结:在泛型调用中指定类型实参时,如果一个类型实参违反了依赖于另一个类型实参的上界约束,编译器现在会报告错误。如果类型形参相互依赖,请使用符合这些约束的类型实参,例如使用 Container<Alpha, AlphaKey>() 而不是 Container<Alpha, BetaKey>()

弃用周期

  • 2.3.0:当泛型调用中的显式类型实参违反类型形参之间的上界约束时报告警告
  • 2.4.0:将该警告提升为错误

弃用对 javaClass 属性的引用

问题KTLC-375

组件:Kotlin/JVM

不兼容变更类型:源码

简要总结:Kotlin 2.4.0 弃用了对 javaClass 属性的属性引用,以减少与 ::class.java 的混淆。使用 .javaClass 获取对象的运行时 Java 类,或使用 ::class.java 获取 Java 类引用。

弃用周期

  • 2.4.0:对 javaClass 属性的属性引用报告警告

对于需要选择性加入的隐式枚举构造函数调用报告错误

问题KTLC-359

组件:核心语言

不兼容变更类型:源码

简要总结:当枚举项隐式调用需要选择性加入的枚举主构造函数时,Kotlin 现在会报告错误。要进行迁移,请在枚举类或每个调用该构造函数的枚举项上添加 @OptIn

弃用周期

  • 2.2.20:当枚举项隐式调用需要选择性加入的枚举主构造函数时报告警告
  • 2.4.0:将该警告提升为错误

禁止在枚举项上使用 inline 修饰符

问题KTLC-361

组件:核心语言

不兼容变更类型:源码

简要总结:如果您在枚举项上使用 inline 修饰符,Kotlin 现在会报告错误。

弃用周期

  • 2.3.0:在枚举项上使用 inline 修饰符时报告警告
  • 2.4.0:将该警告提升为错误

禁止在注解调用和参数默认值之外使用数组字面量

问题KTLC-369

组件:核心语言

不兼容变更类型:源码

简要总结:在注解调用和注解参数默认值之外使用数组字面量现在会导致错误。要进行迁移,请使用 arrayOf(...),例如使用 Roles(arrayOf("admin", "user")) 而不是 Roles(["admin", "user"])

弃用周期

  • 2.3.0:对注解调用和注解参数默认值之外的数组字面量报告警告
  • 2.4.0:将该警告提升为错误

在 CLI 编译器模式下禁止使用 _root_ide_package_

问题KTLC-378

组件:编译器

不兼容变更类型:源码

简要总结:在 CLI 编译器模式下使用仅限 IDE 的 _root_ide_package_ 限定符现在会导致错误。

弃用周期

  • 2.3.20:对 CLI 编译器模式下的 _root_ide_package_ 引用报告警告
  • 2.4.0:将该警告提升为错误

修正带有可变数量实参转换的函数引用的相等性

问题KTLC-385

组件:Kotlin/JVM

不兼容变更类型:行为

简要总结:Kotlin/JVM 现在将具有不同转换的函数引用视为不相等。以前,当同一个函数引用还使用另一种转换时,Kotlin/JVM 在相等性检查中会忽略可变数量实参转换,因此即使只有一侧使用了可变数量实参转换,getDefault(::foo) == getDefaultAndVararg(::foo) 也可能返回 true

弃用周期

  • 2.4.0:引入新行为

强制对伴生对象访问进行选择性加入

问题KTLC-386

组件:核心语言

不兼容变更类型:源码

简要总结:当类名引用解析为需要选择性加入的伴生对象时,Kotlin 现在会报告选择性加入错误。例如,如果 C 解析为标记有选择性加入注解的伴生对象,则 val p = C 需要选择性加入。

弃用周期

  • 2.3.20:当伴生对象访问需要选择性加入时报告警告
  • 2.4.0:对于 ERROR 级别的选择性加入要求,将其提升为错误

报告来自带有嵌套泛型实参的超类型的类型不匹配

问题KTLC-372

组件:核心语言

不兼容变更类型:源码

简要总结:当编译器检测到涉及带有嵌套泛型实参的超类型的类型不匹配时,现在会报告错误。以前,编译器可能会漏掉这种不匹配,从而导致稍后出现 ClassCastException 失败。要进行迁移,请使用与接收者的泛型类型匹配的类型实参,或移除显式类型实参以便编译器可以进行推断。

弃用周期

  • 2.4.0:对涉及带有嵌套泛型实参的超类型的类型不匹配报告错误

禁止包含不可访问声明的推断类型

问题KTLC-363

组件:核心语言

不兼容变更类型:源码

简要总结:使用包含在当前作用域内不可访问的声明的推断类型现在会导致错误。

弃用周期

  • 2.3.0:当推断类型包含在当前作用域内不可访问的声明时报告警告
  • 2.4.0:将该警告提升为错误

标准库

弃用 kotlin.io.readLine() 函数

问题KTLC-394

组件:kotlin-stdlib

不兼容变更类型:源码

简要总结kotlin.io.readLine() 函数已弃用。请使用 readln() 函数代替 readLine()!!,并使用 readlnOrNull() 函数代替 readLine()

弃用周期

  • 2.4.0:使用 kotlin.io.readLine() 时报告警告

弃用 AbstractCoroutineContextKey 及相关 API

问题KT-84970

组件:kotlin-stdlib

不兼容变更类型:源码

简要总结AbstractCoroutineContextKey 类及其相关 API 自 Kotlin 1.3 以来一直处于实验性阶段,且已被证明容易出错。因此,该类以及相关的 getPolymorphicElement()minusPolymorphicKey() 函数已被弃用。

弃用周期

  • 2.4.0:使用已弃用的 API 时报告警告

更改 Random.nextDouble() 处理无限边界的契约

问题KT-84368

组件:kotlin-stdlib

不兼容变更类型:行为

简要总结Random.nextDouble(until) 的文档契约现在要求 until 边界必须是有限的。请改用有限边界。

弃用周期

  • 2.4.0:启用新行为

工具

弃用旧版 Kotlin/JS 编译器类型选择 API

问题KT-64275, KT-84753

组件:Gradle

不兼容变更类型:源码

简要总结:Kotlin 2.4.0 移除了与选择旧版 Kotlin/JS 编译器类型相关的已弃用 Gradle API。

此外,KotlinJsCompilerType 枚举和带有编译器类型形参的 KotlinProjectExtension.js() 重载已被弃用。要进行迁移,请从 js() 目标声明中移除编译器类型实参,并改用 js {} 块。

弃用周期

  • 1.8.0:弃用旧版 Kotlin/JS 编译器类型常量
  • 2.4.0:移除已弃用的旧版编译器类型 API,并在使用 KotlinJsCompilerType 或带有编译器类型形参的 KotlinProjectExtension.js() 重载时报告警告

弃用 Kotlin Android 扩展中的 sourceSets

问题KT-74451

组件:Gradle

不兼容变更类型:源码

简要总结KotlinAndroidProjectExtension 中的 sourceSets 属性已弃用。要进行迁移,请改为通过 Android Gradle 插件的 android { sourceSets { ... } } 块配置源集。

弃用周期

  • 2.4.0:从 KotlinAndroidProjectExtension 访问 sourceSets 时报告警告

移除 Kotlin/Native Apple 框架的可消耗配置

问题KT-74503, KT-82230

组件:Gradle

不兼容变更类型:源码

简要总结:Kotlin 2.4.0 移除了将 Kotlin/Native Apple 框架作为外发构件暴露的已生成的 Gradle 可消耗配置 (consumable configurations)。

弃用周期

  • 2.4.0:移除 Kotlin/Native Apple 框架的可消耗配置

从 Kotlin Gradle 插件中移除已弃用的任务、编译和 DSL API

问题KT-85509

组件:Gradle

不兼容变更类型:源码

简要总结:Kotlin 2.4.0 移除了以下已弃用的 Kotlin Gradle 插件 API:

编译任务配置 API:

  • KotlinJvmCompile.parentKotlinOptions
  • KotlinJvmCompile.moduleName
  • KotlinJvmFactory.createKotlinJvmOptions()
  • KotlinCompileKotlin2JsCompile 任务中的 BaseKotlinCompile.moduleName

Kotlin 多平台层次结构和目标 API:

  • DeprecatedKotlinTargetHierarchyDsl
  • KotlinMultiplatformExtension.targetHierarchy
  • KotlinTargetComponent.sourcesArtifacts
  • KotlinTarget.sourceSets
  • KotlinHierarchyBuilder.withoutCompilations()
  • KotlinHierarchyBuilder.filterCompilations()
  • KotlinHierarchyBuilder.withWasm()
  • KotlinCompilation.defaultSourceSetName

Kotlin 编译任务 API:

  • KotlinCompilation.compileKotlinTaskProvider
  • KotlinCompilation.compileKotlinTask

Kotlin 依赖项处理程序 API:

  • KotlinDependencyHandler.enforcedPlatform()
  • KotlinDependencyHandler.platform() 其他已弃用的任务和扩展 API:
  • KaptExtension.processors
  • KotlinTest.excludes
  • KotlinTest.fileResolver
  • KotlinTest.execHandleFactory
  • IncrementalSyncTask.destinationDir

要进行迁移,请停止使用这些 API,并改用弃用诊断信息中建议的替代方案。

弃用周期

  • 2.4.0:移除已弃用的 API

弃用显式缩减的类路径快照配置

问题KT-75837

组件:构建工具 API

不兼容变更类型:源码

简要总结ClasspathSnapshotBasedIncrementalCompilationApproachParameters 中的 shrunkClasspathSnapshot 配置参数已弃用。由于缩减的类路径快照是内部增量编译缓存,编译器现在会在增量编译器元数据 workingDirectory 下自动创建并管理它。要进行迁移,请使用自动管理的快照文件,而不是向 shrunkClasspathSnapshot 传递值。

弃用周期

  • 2.4.0:使用 shrunkClasspathSnapshot 时报告警告

移除冗余的 ABI 验证 Gradle DSL 元素

问题KT-80685

组件:Gradle

不兼容变更类型:源码

简要总结:Kotlin 2.4.0 简化了 ABI 验证 Gradle DSL 并移除了冗余的配置项。要进行迁移,请直接在 abiValidation {} 而不是 abiValidation { legacyDump { ... } } 中配置报告设置,移除 abiValidation { klib { enabled = ... } },并使用 keepLocallyUnsupportedTargets 代替 klib.keepUnsupportedTargets

弃用周期

  • 2.4.0:移除冗余的 ABI 验证 DSL 元素

弃用过时的 Compose 编译器 Gradle 插件选项

问题KT-85343

组件:Gradle

不兼容变更类型:源码

简要总结:在 Kotlin 2.4.0 中,以下已弃用的 Compose 编译器 Gradle 插件选项在使用时现在会报告错误:

  • generateFunctionKeyMetaClasses
  • enableIntrinsicRemember
  • enableNonSkippingGroupOptimization
  • enableStrongSkippingMode
  • stabilityConfigurationFile
  • ComposeFeatureFlag.StrongSkipping
  • ComposeFeatureFlag.IntrinsicRemember

请使用 featureFlags 代替已弃用的功能选项,并使用 stabilityConfigurationFiles 代替 stabilityConfigurationFile

弃用周期

  • 2.0.20:对 enableIntrinsicRememberenableNonSkippingGroupOptimizationenableStrongSkippingMode 报告警告
  • 2.1.0:对 stabilityConfigurationFile 报告警告
  • 2.4.0:将这些警告提升为错误

对过时的 Kotlin/Native Gradle 任务 API 报告错误

问题KT-85510

组件:Gradle

不兼容变更类型:源码

简要总结:以下已弃用的 Kotlin/Native Gradle 任务 API 在使用时现在会报告错误:

AbstractKotlinNativeCompile 属性:

  • additionalCompilerOptions
  • languageSettings
  • progressiveMode

KotlinNativeCompile 属性:

  • moduleName
  • konanDataDir
  • konanHome
  • languageVersion
  • apiVersion
  • enabledLanguageFeatures
  • optInAnnotationsInUse
  • additionalCompilerOptions

CInteropProcess 属性:

  • outputFile
  • konanDataDir
  • konanHome
  • defFile

KotlinNativeLink 属性:

  • languageSettings
  • additionalCompilerOptions
  • konanDataDir
  • konanHome

此外,KotlinNativeLink.compilation 属性已被移除。

弃用周期

  • 2.4.0:对已弃用的 Kotlin/Native Gradle 任务 API 报告错误,移除 KotlinNativeLink.compilation 属性