Kotlin 2.1.x 兼容性指南
“保持语言现代性”与“舒适的更新”是 Kotlin 语言设计的基本原则。前者指出应当移除阻碍语言演进的结构,而后者则说明这种移除应当事先进行充分沟通,以使代码迁移尽可能平滑。
虽然大多数语言变更已经通过其他渠道(如更新日志或编译器警告)发布,但本文档对这些变更进行了汇总,为从 Kotlin 2.0 迁移到 Kotlin 2.1 提供完整的参考。
基本术语
本文档中引入了几种兼容性类型:
- 源码 (source):源码不兼容的变更会导致以前可以正常编译(没有错误或警告)的代码无法再编译。
- 二进制 (binary):如果交换两个二进制构件不会导致加载或链接错误,则称它们为二进制兼容。
- 行为 (behavioral):如果同一个程序在应用变更前后表现出不同的行为,则称该变更为行为不兼容。
请记住,这些定义仅针对纯 Kotlin。从其他语言(例如 Java)的角度来看,Kotlin 代码的兼容性不在本文档的讨论范围内。
语言
移除 1.4 和 1.5 版本的语言版本
问题:KT-60521
组件:核心语言
不兼容变更类型:源码
简要摘要:Kotlin 2.1 引入了语言版本 2.1,并移除了对语言版本 1.4 和 1.5 的支持。语言版本 1.6 和 1.7 已被弃用。
弃用周期:
- 1.6.0:针对语言版本 1.4 报告警告
- 1.9.0:针对语言版本 1.5 报告警告
- 2.1.0:针对语言版本 1.6 和 1.7 报告警告;将语言版本 1.4 和 1.5 的警告提升为错误
更改 Kotlin/Native 上 typeOf() 函数的行为
问题:KT-70754
组件:核心语言
不兼容变更类型:行为
简要摘要:Kotlin/Native 上
typeOf()函数的行为已与 Kotlin/JVM 对齐,以确保跨平台的一致性。弃用周期:
- 2.1.0:对齐 Kotlin/Native 上的
typeOf()函数行为
禁止通过类型形参的界限公开类型
问题:KT-69653
组件:核心语言
不兼容变更类型:源码
简要摘要:现在禁止通过类型形参界限公开具有较低可见性的类型,以解决类型可见性规则中的不一致问题。 此变更确保类型形参上的界限遵循与类相同的可见性规则,从而防止出现 JVM 中的 IR 验证错误等问题。
弃用周期:
- 2.1.0:针对通过具有较低可见性的类型形参界限公开类型的行为报告警告
- 2.2.0:将该警告提升为错误
禁止继承同名的抽象 var 属性和 val 属性
问题:KT-58659
组件:核心语言
不兼容变更类型:源码
简要摘要:如果一个类从接口继承了一个抽象
var属性,并从超类继承了一个同名的val属性,现在会触发编译错误。这解决了在此类情况下由于缺少 setter 而导致的运行时崩溃。弃用周期:
- 2.1.0:当一个类从接口继承抽象
var属性并从超类继承同名val属性时,报告警告(或在渐进模式下报告错误)- 2.2.0:将该警告提升为错误
访问未初始化的枚举条目时报告错误
问题:KT-68451
组件:核心语言
不兼容变更类型:源码
简要摘要:现在,如果在枚举类或条目初始化期间访问未初始化的枚举条目,编译器将报告错误。这使行为与成员属性初始化规则一致,从而防止运行时异常并确保逻辑一致。
弃用周期:
- 2.1.0:访问未初始化的枚举条目时报告错误
K2 智能转换 (smart cast) 传递的变化
问题:KTLC-34
组件:核心语言
不兼容变更类型:行为
简要摘要:K2 编译器通过为推断变量(如
val x = y)引入类型信息的双向传递,更改了其在智能转换传递方面的行为。显式类型的变量(如val x: T = y)不再传递类型信息,从而确保更严格地遵守声明的类型。弃用周期:
- 2.1.0:启用新行为
修正 Java 子类中成员扩展属性重写的处理
问题:KTLC-35
组件:核心语言
不兼容变更类型:行为
简要摘要:由 Java 子类重写的成员扩展属性的 getter 现在在子类的作用域中被隐藏,使其行为与常规 Kotlin 属性一致。
弃用周期:
- 2.1.0:启用新行为
修正重写 protected val 的 var 属性的 getter 和 setter 的可见性对齐
问题:KTLC-36
组件:核心语言
不兼容变更类型:二进制
简要摘要:重写
protected val属性的var属性的 getter 和 setter 的可见性现在保持一致,两者都继承被重写的val属性的可见性。弃用周期:
- 2.1.0:在 K2 中强制对 getter 和 setter 使用一致的可见性;K1 不受影响
将 JSpecify 为 null 性不匹配诊断的严重级别提升为错误
问题:KTLC-11
组件:核心语言
不兼容变更类型:源码
简要摘要:来自
org.jspecify.annotations的为 null 性不匹配(如@NonNull、@Nullable和@NullMarked)现在被视为错误而非警告,从而对 Java 互操作性强制执行更严格的类型安全。要调整这些诊断的严重级别,请使用-Xnullability-annotations编译器选项。弃用周期:
- 1.6.0:针对潜在的为 null 性不匹配报告警告
- 1.8.20:将警告扩展到特定的 JSpecify 注解,包括:
@Nullable、@NullnessUnspecified、@NullMarked以及org.jspecify.nullness中的旧版注解(JSpecify 0.2 及更早版本)- 2.0.0:增加对
@NonNull注解的支持- 2.1.0:将 JSpecify 注解的默认模式更改为
strict,将警告转换为错误;使用[email protected]:warning或[email protected]:ignore来覆盖默认行为
更改重载解析,在歧义情况下优先选择扩展函数而非 invoke 调用
问题:KTLC-37
组件:核心语言
不兼容变更类型:行为
简要摘要:重载解析现在在歧义情况下一致地优先选择扩展函数而非 invoke 调用。这解决了局部函数和属性在解析逻辑上的不一致。该变更仅在重新编译后生效,不影响预编译的二进制文件。
弃用周期:
- 2.1.0:更改重载解析,对于签名匹配的扩展函数,一致地优先选择扩展函数而非
invoke调用;此变更仅在重新编译后应用,不影响预编译的二进制文件
禁止在 JDK 函数接口的 SAM 构造函数中从 lambda 返回可空值
问题:KTLC-42
组件:核心语言
不兼容变更类型:源码
简要摘要:如果在 JDK 函数接口的 SAM 构造函数中,指定的类型实参是非空的,那么从 lambda 返回可空值现在将触发编译错误。这解决了为 null 性不匹配可能导致运行时异常的问题,确保了更严格的类型安全。
弃用周期:
- 2.0.0:针对 JDK 函数接口的 SAM 构造函数中的可空返回值报告弃用警告
- 2.1.0:默认启用新行为
修正 Kotlin/Native 中私有成员与公共成员冲突的处理
问题:KTLC-43
组件:核心语言
不兼容变更类型:行为
简要摘要:在 Kotlin/Native 中,私有成员不再重写或与超类中的公共成员冲突,其行为与 Kotlin/JVM 一致。这解决了重写解析中的不一致,并消除了由独立编译引起的意外行为。
弃用周期:
- 2.1.0:Kotlin/Native 中的私有函数和属性不再重写或影响超类中的公共成员,与 JVM 行为保持一致
禁止在公共内联函数中访问私有运算符函数
问题:KTLC-71
组件:核心语言
不兼容变更类型:源码
简要摘要:私有运算符函数(如
getValue()、setValue()、provideDelegate()、hasNext()和next())不再能在公共内联函数中被访问。弃用周期:
- 2.0.0:针对在公共内联函数中访问私有运算符函数报告弃用警告
- 2.1.0:将该警告提升为错误
禁止向带有 @UnsafeVariance 注解的不变性参数传递无效实参
问题:KTLC-72
组件:核心语言
不兼容变更类型:源码
简要摘要:编译器现在在类型检查期间忽略
@UnsafeVariance注解,从而对不变性类型参数强制执行更严格的类型安全。这可以防止依赖@UnsafeVariance来绕过预期类型检查的无效调用。弃用周期:
- 2.1.0:激活新行为
为警告级别 Java 类型的错误级别可空实参报告为 null 性错误
问题:KTLC-100
组件:核心语言
不兼容变更类型:源码
简要摘要:编译器现在可以检测 Java 方法中的为 null 性不匹配,其中警告级别的可空类型包含具有更严格的错误级别为 null 性的类型实参。这确保了以前被忽略的类型实参错误能被正确报告。
弃用周期:
- 2.0.0:针对具有更严格类型实参的 Java 方法中的为 null 性不匹配报告弃用警告
- 2.1.0:将该警告提升为错误
报告对不可访问类型的隐式用法
问题:KTLC-3
组件:核心语言
不兼容变更类型:源码
简要摘要:编译器现在报告在函数文字和类型实参中对不可访问类型的用法,从而防止因类型信息不完整而导致的编译和运行时失败。
弃用周期:
- 2.0.0:针对具有不可访问非泛型类型的形参或接收器的函数文字,以及具有不可访问类型实参的类型报告警告;针对具有不可访问泛型类型的形参或接收器的函数文字,以及在特定场景下具有不可访问泛型类型实参的类型报告错误
- 2.1.0:针对具有不可访问非泛型类型的形参和接收器的函数文字,将警告提升为错误
- 2.2.0:针对具有不可访问类型实参的类型,将警告提升为错误
标准库
弃用针对 Char 和 String 的区域性敏感大小写转换函数
问题:KT-43023
组件:kotlin-stdlib
不兼容变更类型:源码
简要摘要:在被弃用的 Kotlin 标准库 API 中,包括针对
Char和String的区域性敏感大小写转换函数,如Char.toUpperCase()和String.toLowerCase()。请使用与区域性无关的替代方案(如String.lowercase())替换它们,或者显式指定区域性以实现区域性敏感行为(如String.lowercase(Locale.getDefault()))。有关 Kotlin 2.1.0 中弃用的 Kotlin 标准库 API 的完整列表,请参阅 KT-71628。
弃用周期:
- 1.4.30:引入与区域性无关的替代方案作为实验性 API
- 1.5.0:通过警告弃用区域性敏感的大小写转换函数
- 2.1.0:将该警告提升为错误
移除 kotlin-stdlib-common JAR 构件
问题:KT-62159
组件:kotlin-stdlib
不兼容变更类型:二进制
简要摘要:
kotlin-stdlib-common.jar构件(以前用于旧版多平台声明元数据)已被弃用,并被.klib文件取代,后者作为通用多平台声明元数据的标准格式。此变更不会影响主要的kotlin-stdlib.jar或kotlin-stdlib-all.jar构件。弃用周期:
- 2.1.0:弃用并移除
kotlin-stdlib-common.jar构件
弃用 appendln(),改为使用 appendLine()
问题:KTLC-27
组件:kotlin-stdlib
不兼容变更类型:源码
简要摘要:
StringBuilder.appendln()已被弃用,建议使用StringBuilder.appendLine()。弃用周期:
- 1.4.0:
appendln()函数被弃用;使用时报告警告- 2.1.0:将该警告提升为错误
弃用 Kotlin/Native 中与冻结 (freezing) 相关的 API
问题:KT-69545
组件:kotlin-stdlib
不兼容变更类型:源码
简要摘要:Kotlin/Native 中以前标记有
@FreezingIsDeprecated注解的冻结相关 API 现在已被弃用。这与新内存管理器的引入一致,该管理器消除了为了线程共享而冻结对象的需求。有关迁移详情,请参阅 Kotlin/Native 迁移指南。弃用周期:
- 1.7.20:通过警告弃用冻结相关 API
- 2.1.0:将该警告提升为错误
更改 Map.Entry 行为,在结构性修改时快速失败 (fail-fast)
问题:KTLC-23
组件:kotlin-stdlib
不兼容变更类型:行为
简要摘要:在其关联的 map 发生结构性修改后访问
Map.Entry键值对,现在将抛出ConcurrentModificationException。弃用周期:
- 2.1.0:当检测到 map 结构性修改时抛出异常
工具
弃用 KotlinCompilationOutput#resourcesDirProvider
问题:KT-69255
组件:Gradle
不兼容变更类型:源码
简要摘要:
KotlinCompilationOutput#resourcesDirProvider字段已被弃用。请改在 Gradle 构建脚本中使用KotlinSourceSet.resources来添加额外的资源目录。弃用周期:
- 2.1.0:
KotlinCompilationOutput#resourcesDirProvider已被弃用
弃用 registerKotlinJvmCompileTask(taskName, moduleName) 函数
问题:KT-69927
组件:Gradle
不兼容变更类型:源码
简要摘要:
registerKotlinJvmCompileTask(taskName, moduleName)函数已被弃用,建议使用新的registerKotlinJvmCompileTask(taskName, compilerOptions, explicitApiMode)函数,该函数现在接受KotlinJvmCompilerOptions。这允许您传递一个compilerOptions实例(通常来自扩展或目标),其值将作为任务选项的约定。弃用周期:
- 2.1.0:
registerKotlinJvmCompileTask(taskName, moduleName)函数已被弃用
弃用 registerKaptGenerateStubsTask(taskName) 函数
问题:KT-70383
组件:Gradle
不兼容变更类型:源码
简要摘要:
registerKaptGenerateStubsTask(taskName)函数已被弃用。请改用新的registerKaptGenerateStubsTask(compileTask, kaptExtension, explicitApiMode)函数。这个新版本允许您将相关KotlinJvmCompile任务中的值关联为约定,从而确保两个任务使用相同的一组选项。弃用周期:
- 2.1.0:
registerKaptGenerateStubsTask(taskName)函数已被弃用
弃用 KotlinTopLevelExtension 和 KotlinTopLevelExtensionConfig 接口
问题:KT-71602
组件:Gradle
不兼容变更类型:行为
简要摘要:
KotlinTopLevelExtension和KotlinTopLevelExtensionConfig接口已被弃用,建议使用新的KotlinTopLevelExtension接口。该接口合并了KotlinTopLevelExtensionConfig、KotlinTopLevelExtension和KotlinProjectExtension以精简 API 层次结构,并提供对 JVM 工具链和编译器属性的正式访问。弃用周期:
- 2.1.0:
KotlinTopLevelExtension和KotlinTopLevelExtensionConfig接口已被弃用
从构建运行时依赖项中移除 kotlin-compiler-embeddable
问题:KT-61706
组件:Gradle
不兼容变更类型:源码
简要摘要:
kotlin-compiler-embeddable依赖项已从 Kotlin Gradle 插件 (KGP) 的运行阶段移除。所需的模块现在直接包含在 KGP 构件中,Kotlin 语言版本限制为 2.0,以支持与 8.2 以下版本的 Gradle Kotlin 运行时兼容。弃用周期:
- 2.1.0:针对使用
kotlin-compiler-embeddable报告警告- 2.2.0:将该警告提升为错误
在 Kotlin Gradle 插件 API 中隐藏编译器符号
问题:KT-70251
组件:Gradle
不兼容变更类型:源码
简要摘要:捆绑在 Kotlin Gradle 插件 (KGP) 中的编译器模块符号(如
KotlinCompilerVersion)已在公共 API 中隐藏,以防止在构建脚本中发生意外访问。弃用周期:
- 2.1.0:访问这些符号时报告警告
- 2.2.0:将该警告提升为错误
增加对多个稳定性配置文件的支持
问题:KT-68345
组件:Gradle
不兼容变更类型:源码
简要摘要:Compose 扩展中的
stabilityConfigurationFile属性已被弃用,建议使用新的stabilityConfigurationFiles属性,该属性允许指定多个配置文件。弃用周期:
- 2.1.0:
stabilityConfigurationFile属性已被弃用
移除弃用的平台插件 ID
问题:KT-65565
组件:Gradle
不兼容变更类型:源码
简要摘要:移除了对以下平台插件 ID 的支持:
kotlin-platform-commonorg.jetbrains.kotlin.platform.common弃用周期:
- 1.3:平台插件 ID 被弃用
- 2.1.0:不再支持平台插件 ID
