13.6.10.4 Kotlin 1.4.x 兼容性指南

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

13.6.10.4 Kotlin 1.4.x 兼容性指南

保持语言的现代性 和 舒适的更新 是 Kotlin 语言设计中的基本原则。前者指出,阻碍语言演进的构造应该被移除;后者指出,这种移除应事先充分沟通,以便代码迁移尽可能顺畅。

虽然大多数语言变更已经通过其他渠道公布过(例如更新日志或编译器警告),但本文汇总了所有这些变更,为从 Kotlin 1.3 迁移到 Kotlin 1.4 提供完整参考。

基本术语

本文介绍了以下几种兼容性:

  • 源码级:源码不兼容的变更会让原本能正常编译(无错误或警告)的代码不再能编译
  • 二进制级:如果互换两个二进制产物不会导致加载或链接错误,则称它们是二进制兼容的
  • 行为级:如果同一个程序在应用变更前后的行为不同,则该变更属于行为不兼容

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

语言与标准库

与 in 中缀运算符和 ConcurrentHashMap 配合时的意外行为

Issue:KT-18053 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.4 将禁止来自以 Java 编写的 java.util.Map 实现者的自动 contains 运算符 弃用周期:- < 1.4:在调用点对有问题的运算符引入警告 - >= 1.4:把该警告提升为错误,可以用 -XXLanguage:-ProhibitConcurrentHashMapContains 临时回退到 1.4 之前的行为

禁止在公共内联成员中访问 protected 成员

Issue:KT-21178 组件:核心语言 不兼容变更类型:源码级 简要说明:Kotlin 1.4 将禁止从公共内联成员访问 protected 成员。弃用周期:- < 1.4:在调用点对有问题的情形引入警告 - 1.4:把该警告提升为错误,可以用 -XXLanguage:-ProhibitProtectedCallFromInline 临时回退到 1.4 之前的行为

带隐式接收者的调用上的契约

Issue:KT-28672 组件:核心语言 不兼容变更类型:行为级 简要说明:在 1.4 中,来自契约的智能转换将在带隐式接收者的调用上可用 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-ContractsOnCallsWithImplicitReceiver 临时回退到 1.4 之前的行为

浮点数比较的不一致行为

Issues:KT-22723 组件:核心语言 不兼容变更类型:行为级 简要说明:从 Kotlin 1.4 起,Kotlin 编译器将使用 IEEE 754 标准比较浮点数 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-ProperIeee754Comparisons 临时回退到 1.4 之前的行为

泛型 lambda 中最后一个表达式不进行智能转换

Issue:KT-15020 组件:核心语言 不兼容变更类型:行为级 简要说明:从 1.4 起,lambda 中最后一个表达式的智能转换将被正确应用 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

不要依赖 lambda 实参的顺序把结果强制转换为 Unit

Issue:KT-36045 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,lambda 实参将被独立解析,不再隐式强制转换为 Unit 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

原始类型与整数字面量类型之间错误的公共父类型导致不健全的代码

Issue:KT-35681 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,原始 Comparable 类型与整数字面量类型之间的公共父类型将更具体 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

若干相等的类型变量被实例化为不同类型导致的类型安全问题

Issue:KT-35679 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,Kotlin 编译器将禁止把相等的类型变量实例化为不同类型 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

交叉类型的子类型关系不正确导致的类型安全问题

Issues:KT-22474 组件:核心语言 不兼容变更类型:源码级 简要说明:在 Kotlin 1.4 中,交叉类型的子类型关系将被细化,以更正确地工作 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

lambda 中空的 when 表达式不再出现类型不匹配

Issue:KT-17995 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,如果空的 when 表达式被用作 lambda 中的最后一个表达式,将会出现类型不匹配 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

带提前 return 的 lambda 在某个返回值中使用整数字面量时推断返回类型为 Any

Issue:KT-20226 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,在存在提前 return 的情况下,lambda 的整数返回类型将更具体 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

带递归类型的星投影的正确捕获

Issue:KT-33012 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,由于递归类型的捕获将更正确地工作,会有更多候选变得适用 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

非合适类型与灵活类型计算公共父类型导致错误结果

Issue:KT-37054 组件:核心语言 不兼容变更类型:行为级 简要说明:从 Kotlin 1.4 起,灵活类型之间的公共父类型将更具体,从而防止运行时错误 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

缺少针对可空类型实参的捕获转换导致的类型安全问题

Issue:KT-35487 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,捕获类型与可空类型之间的子类型关系将更正确,从而防止运行时错误 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

未经检查的转换之后为协变类型保留交叉类型

Issue:KT-37280 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,协变类型的未经检查转换会为智能转换产生交叉类型,而不是该未经检查转换的类型。弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

由于使用 this 表达式导致类型变量从构建器推断中泄漏

Issue:KT-32126 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,如果没有其他合适的约束,则禁止在 sequence {} 之类的构建器函数内部使用 this 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

带可空类型实参的逆变类型的错误重载解析

Issue:KT-31670 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,如果某个函数接受逆变类型实参的两个重载仅类型可空性不同(例如 In<T> 和 In<T?>),则可空类型被认为更具体。弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

带非嵌套递归约束的构建器推断

Issue:KT-34975 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,像 sequence {} 这样、其类型依赖所传 lambda 内部递归约束的构建器函数会导致编译错误。弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

过早固定类型变量导致矛盾的约束系统

Issue:KT-25175 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,在某些情况下类型推断不再那么急于固定,从而能够找到不矛盾的约束系统。弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-NewInference 临时回退到 1.4 之前的行为。请注意该标志还会禁用若干新的语言特性。

禁止在 open 函数上使用 tailrec 修饰符

Issue:KT-18541 组件:核心语言 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,函数不能同时具有 open 和 tailrec 修饰符。弃用周期:- < 1.4:对同时具有 open 和 tailrec 修饰符的函数报告警告(在渐进模式下报告错误)。- >= 1.4:把该警告提升为错误。

伴生对象的 INSTANCE 字段可见性高于伴生对象类本身

Issue:KT-11567 组件:Kotlin/JVM 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,如果伴生对象是私有的,那么它的 INSTANCE 字段也将是私有的 弃用周期:- < 1.4:编译器生成带弃用标志的 INSTANCE 对象 - >= 1.4:伴生对象的 INSTANCE 字段具有正确的可见性

在无 finally 的内部 try 块的 catch 区间中未排除插入到 return 之前的父级 finally 块

Issue:KT-31923 组件:Kotlin/JVM 不兼容变更类型:行为级 简要说明:从 Kotlin 1.4 起,嵌套的 try/catch 块的 catch 区间将被正确计算 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-ProperFinally 临时回退到 1.4 之前的行为

在协变和泛型特化的覆盖中,在返回类型位置使用内联类的装箱版本

Issues:KT-30419 组件:Kotlin/JVM 不兼容变更类型:行为级 简要说明:从 Kotlin 1.4 起,使用协变和泛型特化覆盖的函数将返回内联类的装箱值 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化

委托给 Kotlin 接口时不在 JVM 字节码中声明受检异常

Issue:KT-35834 组件:Kotlin/JVM 不兼容变更类型:源码级 简要说明:Kotlin 1.4 在委托给 Kotlin 接口时不会生成受检异常 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-DoNotGenerateThrowsForDelegatedKotlinMembers 临时回退到 1.4 之前的行为

修改对带单个 vararg 参数的方法进行签名多态调用的行为,以避免把实参再包装进另一个数组

Issue:KT-35469 组件:Kotlin/JVM 不兼容变更类型:源码级 简要说明:Kotlin 1.4 在签名多态调用中不会把实参再包装进另一个数组 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化

当 KClass 用作泛型参数时注解中的泛型签名不正确

Issue:KT-35207 组件:Kotlin/JVM 不兼容变更类型:源码级 简要说明:当 KClass 用作泛型参数时,Kotlin 1.4 会修复注解中错误的类型映射 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化

禁止在签名多态调用中使用展开运算符

Issue:KT-35226 组件:Kotlin/JVM 不兼容变更类型:源码级 简要说明:Kotlin 1.4 将禁止在签名多态调用中使用展开运算符(*)弃用周期:- < 1.4:对在签名多态调用中使用展开运算符报告警告 - >= 1.5:把该警告提升为错误,可以用 -XXLanguage:-ProhibitSpreadOnSignaturePolymorphicCall 临时回退到 1.4 之前的行为

修改尾递归优化函数默认值的初始化顺序

Issue:KT-31540 组件:Kotlin/JVM 不兼容变更类型:行为级 简要说明:从 Kotlin 1.4 起,尾递归函数的初始化顺序将与普通函数相同 弃用周期:- < 1.4:在有问题的函数的声明处报告警告 - >= 1.4:行为发生变化,可以用 -XXLanguage:-ProperComputationOrderOfTailrecDefaultParameters 临时回退到 1.4 之前的行为

不为非 const 的 val 生成 ConstantValue 属性

Issue:KT-16615 组件:Kotlin/JVM 不兼容变更类型:行为级 简要说明:从 Kotlin 1.4 起,编译器不会为非 const 的 val 生成 ConstantValue 属性 弃用周期:- < 1.4:通过 IntelliJ IDEA 检查报告警告 - >= 1.4:行为发生变化,可以用 -XXLanguage:-NoConstantValueAttributeForNonConstVals 临时回退到 1.4 之前的行为

对 open 方法使用 @JvmOverloads 生成的桥接重载应为 final

Issue:KT-33240 组件:Kotlin/JVM 不兼容变更类型:源码级 简要说明:带 @JvmOverloads 的函数的桥接重载将生成为 final 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化,可以用 -XXLanguage:-GenerateJvmOverloadsAsFinal 临时回退到 1.4 之前的行为

返回 kotlin.Result 的 lambda 现在返回装箱值而不是非装箱值

Issue:KT-39198 组件:Kotlin/JVM 不兼容变更类型:行为级 简要说明:从 Kotlin 1.4 起,返回 kotlin.Result 类型值的 lambda 将返回装箱值而不是非装箱值 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化

统一 null 检查抛出的异常

Issue:KT-22275 组件:Kotlin/JVM 不兼容变更类型:行为级 简要说明:从 Kotlin 1.4 开始,所有运行时 null 检查都会抛出 java.lang.NullPointerException 弃用周期:- < 1.4:运行时 null 检查抛出不同的异常,例如 KotlinNullPointerException、IllegalStateException、IllegalArgumentException 和 TypeCastException - >= 1.4:所有运行时 null 检查都抛出 java.lang.NullPointerException。可以用 -Xno-unified-null-checks 临时回退到 1.4 之前的行为

在数组/列表操作 contains、indexOf、lastIndexOf 中比较浮点值:IEEE 754 还是全序

Issue:KT-28753 组件:kotlin-stdlib(JVM)不兼容变更类型:行为级 简要说明:由 Double/FloatArray.asList() 返回的 List 实现将实现 contains、indexOf 和 lastIndexOf,使它们使用全序相等 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化

逐步把集合 min 和 max 函数的返回类型改为不可为空

Issue:KT-38854 组件:kotlin-stdlib(JVM)不兼容变更类型:源码级 简要说明:集合 min 和 max 函数的返回类型将在 1.6 中改为不可为空 弃用周期:- 1.4:引入 ...OrNull 函数作为同义替代,并弃用受影响的 API(详见该 issue)- 1.5.x:把受影响 API 的弃用级别提升为错误 - >=1.6:重新引入受影响的 API,但返回类型为不可为空

弃用 appendln,改用 appendLine

Issue:KT-38754 组件:kotlin-stdlib(JVM)不兼容变更类型:源码级 简要说明:StringBuilder.appendln() 将被弃用,改用 StringBuilder.appendLine() 弃用周期:- 1.4:引入 appendLine 函数作为 appendln 的替代并弃用 appendln - >=1.5:把弃用级别提升为错误

弃用浮点类型到 Short 和 Byte 的转换

Issue:KT-30360 组件:kotlin-stdlib(JVM)不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,浮点类型到 Short 和 Byte 的转换将被弃用 弃用周期:- 1.4:弃用 Double.toShort()/toByte() 和 Float.toShort()/toByte() 并提出替代方案 - >=1.5:把弃用级别提升为错误

在无效的 startIndex 上让 Regex.findAll 快速失败

Issue:KT-28356 组件:kotlin-stdlib 不兼容变更类型:行为级 简要说明:从 Kotlin 1.4 起,findAll 将得到改进:在进入 findAll 的那一刻检查 startIndex 是否位于输入字符序列的有效位置索引范围内,如果不是则抛出 IndexOutOfBoundsException 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化

移除已弃用的 kotlin.coroutines.experimental

Issue:KT-36083 组件:kotlin-stdlib 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,已弃用的 kotlin.coroutines.experimental API 从标准库中移除 弃用周期:- < 1.4:kotlin.coroutines.experimental 以 ERROR 级别被弃用 - >= 1.4:从标准库中移除 kotlin.coroutines.experimental。在 JVM 上提供了单独的兼容性产物(详见该 issue)。

移除已弃用的 mod 运算符

Issue:KT-26654 组件:kotlin-stdlib 不兼容变更类型:源码级 简要说明:从 Kotlin 1.4 起,数值类型上的 mod 运算符从标准库中移除 弃用周期:- < 1.4:mod 以 ERROR 级别被弃用 - >= 1.4:从标准库中移除 mod

隐藏 Throwable.addSuppressed 成员并优先使用扩展

Issue:KT-38777 组件:kotlin-stdlib 不兼容变更类型:行为级 简要说明:现在优先使用 Throwable.addSuppressed() 扩展函数,而不是 Throwable.addSuppressed() 成员函数 弃用周期:- < 1.4:旧行为(详见该 issue)- >= 1.4:行为发生变化

capitalize 应把二合字母转换为标题大小写

Issue:KT-38817 组件:kotlin-stdlib 不兼容变更类型:行为级 简要说明:String.capitalize() 函数现在会以标题大小写大写 塞尔维亚-克罗地亚语 Gaj 拉丁字母表中的二合字母(Dž 而不是 DŽ)弃用周期:- < 1.4:二合字母以大写形式大写(DŽ)- >= 1.4:二合字母以标题大小写形式大写(Dž)

工具

在 Windows 上带分隔符字符的编译器参数必须用双引号传递

Issue:KT-41309 组件:CLI 不兼容变更类型:行为级 简要说明:在 Windows 上,包含分隔符字符(空白、=、;、,)的 kotlinc.bat 参数现在需要使用双引号(")弃用周期:- < 1.4:所有编译器参数都不加引号传递 - >= 1.4:包含分隔符字符(空白、=、;、,)的编译器参数需要使用双引号(")

KAPT:属性的合成 $annotations() 方法名已改变

Issue:KT-36926 组件:KAPT 不兼容变更类型:行为级 简要说明:KAPT 为属性生成的合成 $annotations() 方法名在 1.4 中发生了变化 弃用周期:- < 1.4:属性的合成 $annotations() 方法名遵循模板 <propertyName>@annotations() - >= 1.4:属性的合成 $annotations() 方法名包含 get 前缀:get<PropertyName>@annotations()