4.3 Kotlin 2.4.x 兼容性指南

原文链接: https://kotlinlang.org/docs/compatibility-guide-24.html

4.3 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:把该警告提升为错误

禁止对确定不兼容的类型进行恒为 false 的 is 检查

问题:KTLC-365 组件:核心语言 不兼容变更类型:源码 简要说明:由于被检查的类型确定不兼容而恒为 false 的 is 检查没有意义,编译器现在会阻止这类检查。这让该行为与其他涉及不兼容类型的操作保持一致。弃用周期:- 2.0.0:对类型确定不兼容的 is 检查报告警告 - 2.4.0:把该警告提升为错误

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

问题:KTLC-283 组件:核心语言 不兼容变更类型:源码 简要说明:编译器现在会阻止内联函数暴露可见性低于该内联函数自身的类型和声明。弃用周期:- 2.3.0:对在内联函数中暴露可见性更低的类型和声明报告警告 - 2.4.0:把该警告提升为错误

变更注解的默认使用处目标选择

问题:KTLC-391 组件:核心语言 不兼容变更类型:二进制 简要说明:Kotlin 2.4.0 更新了把注解传播到参数、属性和字段的默认规则。这可能影响重新编译后的注解处理、反射和二进制元数据。当你没有指定使用处目标时,编译器现在会使用 param 和 property(如果适用),并且只在 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 可空性注解

问题:KTLC-285 组件:核心语言 不兼容变更类型:源码 简要说明:对于使用 jakarta.annotation.Nullable 或 jakarta.annotation.Nonnull 的 Java 声明,编译器现在会在 Kotlin 中强制执行其声明的可空性。如果你把被这些注解标记为可空的 Java 声明赋值给非空的 Kotlin 类型,编译器会报告错误。弃用周期:- 2.2.0:对带 Jakarta 可空性注解的 Java 声明中的可空性不匹配报告警告 - 2.4.0:把该警告提升为错误

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

问题:KTLC-388 组件:核心语言 不兼容变更类型:源码 简要说明:编译器现在会检查可调用引用的左侧部分,如果内部类在限定符中错误的位置包含类型实参,就会报告警告。要迁移,请更新该引用,使每个类型实参都属于声明它的类。例如,写完整类型 Outer<Int>.Inner<String>::toString,而不是 Inner<String, Int>::toString。弃用周期:- 2.4.0:当可调用引用左侧部分的类型实参属于限定符的另一部分时报告警告

对来自具有可空上界的已具体化类型参数的类字面量报告错误

问题:KTLC-370 组件:核心语言 不兼容变更类型:源码 简要说明:当你对类型来自具有可空上界的已具体化类型参数的表达式使用 ::class 时,编译器现在会报告错误。如果你对这类表达式使用 ::class,请先用显式的空值检查或 !! 运算符把该值变为非空。弃用周期:- 2.3.0:当对类型来自具有可空上界的已具体化类型参数的表达式使用 ::class 时报告警告 - 2.4.0:把该警告提升为错误

禁止在匿名对象中先初始化后声明

问题:KTLC-290 组件:核心语言 不兼容变更类型:源码 简要说明:当你在匿名对象的 init 块中初始化某个属性、但该属性的声明出现在后面时,Kotlin 现在会报告错误。弃用周期:- 2.2.20:当匿名对象中的 init 块在属性声明之前初始化该属性时报告警告 - 2.4.0:把该警告提升为错误

对使用非抽象 Java 密封类的 when 表达式强制要求穷尽性

问题:KTLC-366 组件:核心语言 不兼容变更类型:源码 简要说明:当你对非抽象 Java 密封类使用 when 表达式时,Kotlin 现在会更严格地检查穷尽性,要求提供 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:把该警告提升为错误

修正带 vararg 转换的函数引用的相等性

问题:KTLC-385 组件:Kotlin/JVM 不兼容变更类型:行为 简要说明:Kotlin/JVM 现在把转换方式不同的函数引用视为不相等。以前,当同一个函数引用还使用了另一种转换时,Kotlin/JVM 会在相等性检查中忽略 vararg 转换,因此即使只有一侧使用了 vararg 转换,getDefault(::foo) == getDefaultAndVararg(::foo) 也可能返回 true。弃用周期:- 2.4.0:引入新行为

对伴生对象访问强制执行选择启用

问题:KTLC-386 组件:核心语言 不兼容变更类型:源码 简要说明:当某个类名引用解析为需要选择启用的伴生对象时,Kotlin 现在会报告选择启用错误。例如,如果 C 解析为带选择启用注解的伴生对象,那么 val p = C 就需要选择启用。弃用周期:- 2.3.20:当伴生对象访问需要选择启用时报告警告 - 2.4.0:对 ERROR 级别的选择启用要求,把该警告提升为错误

报告带嵌套泛型实参的父类型引发的类型不匹配

问题:KTLC-372 组件:核心语言 不兼容变更类型:源码 简要说明:当编译器检测到涉及带嵌套泛型实参的父类型的类型不匹配时,Kotlin 现在会报告错误。以前编译器可能漏掉这种不匹配,之后会以 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() 时报告警告

问题: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 配置。弃用周期:- 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() * KotlinCompile 和 Kotlin2JsCompile 任务中的 BaseKotlinCompile.moduleName Kotlin Multiplatform 层级与目标 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:对 enableIntrinsicRemember、enableNonSkippingGroupOptimization 和 enableStrongSkippingMode 报告警告 - 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 属性

对编译器参数值的大小写不匹配报告警告

问题:KT-86059 组件:构建工具 API 不兼容变更类型:源码 简要说明:接受固定取值集合的编译器参数以前在处理字母大小写时并不一致:有些接受任意大小写,有些则要求完全匹配。构建工具 API现在对这些值接受任意大小写,但会报告警告,例如 Case mismatch for -module-kind: expected 'commonjs', got 'CommonJS'。要迁移,请使用编译器参考中为该参数列出的大小写形式。弃用周期:- 2.4.20:当编译器参数值的字母大小写与期望值不匹配时报告警告