4.3 Kotlin 2.4.x 兼容性指南
13 分钟阅读
原文链接: 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:对值参数过多的operatorgetValue()和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()时报告警告
弃用 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 配置。弃用周期:- 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.moduleNameKotlin Multiplatform 层级与目标 API:*DeprecatedKotlinTargetHierarchyDsl*KotlinMultiplatformExtension.targetHierarchy*KotlinTargetComponent.sourcesArtifacts*KotlinTarget.sourceSets*KotlinHierarchyBuilder.withoutCompilations()*KotlinHierarchyBuilder.filterCompilations()*KotlinHierarchyBuilder.withWasm()*KotlinCompilation.defaultSourceSetNameKotlin 编译任务 API:*KotlinCompilation.compileKotlinTaskProvider*KotlinCompilation.compileKotlinTaskKotlin 依赖处理 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*progressiveModeKotlinNativeCompile属性:*moduleName*konanDataDir*konanHome*languageVersion*apiVersion*enabledLanguageFeatures*optInAnnotationsInUse*additionalCompilerOptionsCInteropProcess属性:*outputFile*konanDataDir*konanHome*defFileKotlinNativeLink属性:*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:当编译器参数值的字母大小写与期望值不匹配时报告警告