Kotlin 1.3.x 相容性指南
_保持語言現代化與舒適的更新_是 Kotlin 語言設計的基本原則。前者指出應移除阻礙語言演進的結構,而後者則說明這種移除應事先進行良好的溝通,以使程式碼遷移盡可能順暢。
雖然大多數語言變更已經透過其他管道(例如更新變更日誌或編譯器警告)宣布,但本文文件對其進行了總結,為從 Kotlin 1.2 遷移到 Kotlin 1.3 提供完整的參考。
基本術語
在本文文件中,我們介紹了幾種相容性:
- 原始碼 (Source):原始碼不相容變更會導致原本可以正常編譯(沒有錯誤或警告)的程式碼無法再編譯
- 二進制 (Binary):如果交換兩個二進制構件不會導致載入或連結錯誤,則稱這兩個二進制構件為二進制相容
- 行為 (Behavioral):如果同一個程式在套用變更前後表現出不同的行為,則稱該變更為行為不相容
請記住,這些定義僅針對純 Kotlin 提供。從其他語言角度(例如 Java)看 Kotlin 程式碼的相容性不在本文文件的討論範圍內。
不相容變更
關於 <clinit> 呼叫的建構函式引數求值順序
問題:KT-19532
組建:Kotlin/JVM
不相容變更類型:行為
簡短摘要:在 1.3 中,相對於類別初始化的求值順序已更改
棄用週期:
- <1.3:舊行為(詳見問題說明)
- >= 1.3:行為已更改, 可使用
-Xnormalize-constructor-calls=disable暫時恢復到 1.3 之前的行為。對此標記的支援將在下一個主要版本中移除。
註解建構函式參數中缺失的 Getter 目標註解
問題:KT-25287
組建:Kotlin/JVM
不相容變更類型:行為
簡短摘要:註解建構函式參數上的 Getter 目標註解將在 1.3 中被正確地寫入類別檔案
棄用週期:
- <1.3:未套用註解建構函式參數上的 Getter 目標註解
- >=1.3:正確套用註解建構函式參數上的 Getter 目標註解,並將其寫入產生的程式碼中
類別建構函式的 @get: 註解中缺失的錯誤
問題:KT-19628
組建:核心語言
不相容變更類型:原始碼
簡短摘要:Getter 目標註解中的錯誤將在 1.3 中被正確回報
棄用週期:
- <1.2:未回報 Getter 目標註解中的編譯錯誤,導致錯誤的程式碼被正常編譯。
- 1.2.x:錯誤僅由工具回報,編譯器仍可在沒有任何警告的情況下編譯此類程式碼
- >=1.3:編譯器也會回報錯誤,導致錯誤的程式碼被拒絕
存取標有 @NotNull 的 Java 型別時的 Nullability 斷言
問題:KT-20830
組建:Kotlin/JVM
不相容變更類型:行為
簡短摘要:對於標有 Not-Null 註解的 Java 型別,Nullability 斷言的產生將更加積極,導致在此處傳遞
null的程式碼更早失敗。棄用週期:
- <1.3:當涉及型別推論時,編譯器可能會遺漏此類斷言,從而允許在針對二進制檔案編譯期間發生潛在的
null傳遞(詳見問題說明)。- >=1.3:編譯器會產生遺漏的斷言。這可能會導致(錯誤地)在此處傳遞
null的程式碼更早失敗。 可使用-XXLanguage:-StrictJavaNullabilityAssertions暫時返回到 1.3 之前的行為。對此標記的支援將在下一個主要版本中移除。
列舉成員上不健全的智慧轉型
問題:KT-20772
組建:核心語言
不相容變更類型:原始碼
簡短摘要:對某個列舉項目成員的智慧轉型將正確地僅套用於該列舉項目
棄用週期:
- <1.3:對某個列舉項目成員的智慧轉型可能會導致對其他列舉項目的相同成員進行不健全的智慧轉型。
- >=1.3:智慧轉型將僅正確地套用於該列舉項目的成員。
-XXLanguage:-SoundSmartcastForEnumEntries將暫時返回舊行為。對此標記的支援將在下一個主要版本中移除。
Getter 中 val 支援欄位的重新指派
問題:KT-16681
組建:核心語言
不相容變更類型:原始碼
簡短摘要:現在禁止在其 Getter 中重新指派
val屬性的支援欄位棄用週期:
- <1.2:Kotlin 編譯器允許在其 Getter 中修改
val的支援欄位。這不僅違反了 Kotlin 語意,還會產生重新指派final欄位的錯誤 JVM 位元組碼。- 1.2.X:對於重新指派
val支援欄位的程式碼回報棄用警告- >=1.3:棄用警告提升為錯誤
在進行迭代的 for 迴圈之前擷取陣列
問題:KT-21354
組建:Kotlin/JVM
不相容變更類型:原始碼
簡短摘要:如果 for 迴圈範圍中的運算式是在迴圈體中更新的區域變數,則此變更會影響迴圈執行。這與在其他容器(如範圍、字元序列和集合)上進行迭代不一致。
棄用週期:
- <1.2:上述程式碼模式可正常編譯,但區域變數的更新會影響迴圈執行
- 1.2.X:如果 for 迴圈中的範圍運算式是在迴圈體中指派的陣列型別區域變數,則回報棄用警告
- 1.3:在這種情況下更改行為,以與其他容器保持一致
列舉項目中的巢狀分類器
問題:KT-16310
組建:核心語言
不相容變更類型:原始碼
簡短摘要:自 Kotlin 1.3 起,禁止在列舉項目中使用巢狀分類器(類別、物件、介面、註解類別、列舉類別)
棄用週期:
- <1.2:列舉項目中的巢狀分類器可正常編譯,但在執行時可能會失敗並拋出例外
- 1.2.X:對巢狀分類器回報棄用警告
- >=1.3:棄用警告提升為錯誤
資料類別覆寫 copy
問題:KT-19618
組建:核心語言
不相容變更類型:原始碼
簡短摘要:自 Kotlin 1.3 起,禁止資料類別覆寫
copy()棄用週期:
- <1.2:覆寫
copy()的資料類別可正常編譯,但在執行時可能會失敗或表現出奇怪的行為- 1.2.X:對覆寫
copy()的資料類別回報棄用警告- >=1.3:棄用警告提升為錯誤
繼承 Throwable 且從外層類別擷取泛型參數的內部類別
問題:KT-17981
組建:核心語言
不相容變更類型:原始碼
簡短摘要:自 Kotlin 1.3 起,內部類別不允許繼承
Throwable棄用週期:
- <1.2:繼承
Throwable的內部類別可正常編譯。如果此類內部類別剛好擷取了泛型參數,則可能導致在執行時失敗的奇怪程式碼模式。- 1.2.X:對繼承
Throwable的內部類別回報棄用警告- >=1.3:棄用警告提升為錯誤
關於包含伴生物件的複雜類別階層之可見性規則
組建:核心語言
不相容變更類型:原始碼
簡短摘要:自 Kotlin 1.3 起,對於涉及伴生物件和巢狀分類器的複雜類別階層,透過短名稱存取的可見性規則更加嚴格。
棄用週期:
- <1.2:舊的可見性規則(詳見問題說明)
- 1.2.X:對將不再能存取的短名稱回報棄用警告。工具建議透過增加全名進行自動遷移。
- >=1.3:棄用警告提升為錯誤。違規程式碼應增加完整的限定詞或明確匯入
非常數的 vararg 註解參數
問題:KT-23153
組建:核心語言
不相容變更類型:原始碼
簡短摘要:自 Kotlin 1.3 起,禁止將非常數值設定為 vararg 註解參數
棄用週期:
- <1.2:編譯器允許為 vararg 註解參數傳遞非常數值,但在位元組碼產生期間實際上會捨棄該值,導致不明顯的行為
- 1.2.X:對此類程式碼模式回報棄用警告
- >=1.3:棄用警告提升為錯誤
區域註解類別
問題:KT-23277
組建:核心語言
不相容變更類型:原始碼
簡短摘要:自 Kotlin 1.3 起不支援區域註解類別
棄用週期:
- <1.2:編譯器可以正常編譯區域註解類別
- 1.2.X:對區域註解類別回報棄用警告
- >=1.3:棄用警告提升為錯誤
區域委派屬性上的智慧轉型
問題:KT-22517
組建:核心語言
不相容變更類型:原始碼
簡短摘要:自 Kotlin 1.3 起,不允許在區域委派屬性上進行智慧轉型
棄用週期:
- <1.2:編譯器允許對區域委派屬性進行智慧轉型,這在委派行為不良的情況下可能導致不健全的智慧轉型
- 1.2.X:區域委派屬性上的智慧轉型被報告為棄用(編譯器發出警告)
- >=1.3:棄用警告提升為錯誤
mod 運算子慣例
問題:KT-24197
組建:核心語言
不相容變更類型:原始碼
簡短摘要:自 Kotlin 1.3 起,禁止宣告
mod運算子,也禁止解析為此類宣告的呼叫棄用週期:
- 1.1.X, 1.2.X:對
operator mod的宣告以及解析為它的呼叫回報警告- 1.3.X:將警告提升為錯誤,但仍允許解析為
operator mod宣告- 1.4.X:不再將呼叫解析為
operator mod
以具名形式將單一元素傳遞給 vararg
問題:KT-20588, KT-20589。另請參閱 KT-20171
組建:核心語言
不相容變更類型:原始碼
簡短摘要:在 Kotlin 1.3 中,將單一元素指派給 vararg 已棄用,應替換為連續的展開 (spread) 和陣列建構。
棄用週期:
- <1.2:以具名形式將一個值元素指派給 vararg 可以正常編譯,並被視為將單一元素指派給陣列,這在將陣列指派給 vararg 時會導致不明顯的行為
- 1.2.X:對此類指派回報棄用警告,建議使用者切換到連續的展開和陣列建構。
- 1.3.X:警告提升為錯誤
- >= 1.4:更改將單一元素指派給 vararg 的語意,使指派陣列等同於指派陣列的展開
目標為 EXPRESSION 的註解保留原則
問題:KT-13762
組建:核心語言
不相容變更類型:原始碼
簡短摘要:自 Kotlin 1.3 起,目標為
EXPRESSION的註解僅允許使用SOURCE保留原則棄用週期:
- <1.2:允許目標為
EXPRESSION且保留原則非SOURCE的註解,但在使用處會被無聲忽略- 1.2.X:對此類註解的宣告回報棄用警告
- >=1.3:警告提升為錯誤
目標為 PARAMETER 的註解不應套用於參數型別
問題:KT-9580
組建:核心語言
不相容變更類型:原始碼
簡短摘要:自 Kotlin 1.3 起,當目標為
PARAMETER的註解被套用於參數型別時,將正確回報關於錯誤註解目標的錯誤棄用週期:
- <1.2:上述程式碼模式可正常編譯;註解被無聲忽略且不存在於位元組碼中
- 1.2.X:對此類用法回報棄用警告
- >=1.3:警告提升為錯誤
Array.copyOfRange 在索引超出範圍時拋出例外,而非擴大回傳的陣列
問題:KT-19489
組建:kotlin-stdlib (JVM)
不相容變更類型:行為
簡短摘要:自 Kotlin 1.3 起,確保
Array.copyOfRange的toIndex引數(代表被複製範圍的不包含結束索引)不大於陣列大小,若大於則拋出IllegalArgumentException。棄用週期:
- <1.3:如果
Array.copyOfRange調用中的toIndex大於陣列大小,範圍中缺失的元素將填入null,這違反了 Kotlin 型別系統的健全性。- >=1.3:檢查
toIndex是否在陣列範圍內,若不在則拋出例外
步長為 Int.MIN_VALUE 和 Long.MIN_VALUE 的 Int 與 Long 級數被禁止,且不允許具現化
問題:KT-17176
組建:kotlin-stdlib (JVM)
不相容變更類型:行為
簡短摘要:自 Kotlin 1.3 起,禁止整數級數的步長值為其整數型別(
Long或Int)的最小負值,因此呼叫IntProgression.fromClosedRange(0, 1, step = Int.MIN_VALUE)將拋出IllegalArgumentException棄用週期:
- <1.3:可以建立步長為
Int.MIN_VALUE的IntProgression,這會產生兩個值[0, -2147483648],這是個不明顯的行為- >=1.3:如果步長是其整數型別的最小負值,則拋出
IllegalArgumentException
對極長序列進行操作時的索引溢位檢查
問題:KT-16097
組建:kotlin-stdlib (JVM)
不相容變更類型:行為
簡短摘要:自 Kotlin 1.3 起,確保
index、count和類似方法對於長序列不會發生溢位。受影響方法的完整列表請參閱問題說明。棄用週期:
- <1.3:由於整數溢位,在極長序列上呼叫此類方法可能會產生負值結果
- >=1.3:在此類方法中偵測溢位並立即拋出例外
統一各平台間以空匹配正規表示式進行分割的結果
問題:KT-21049
組建:kotlin-stdlib (JVM)
不相容變更類型:行為
簡短摘要:自 Kotlin 1.3 起,統一各平台間以空匹配正規表示式進行
split方法呼叫的行為棄用週期:
- <1.3:比較 JS、JRE 6、JRE 7 與 JRE 8+ 時,上述呼叫的行為有所不同
- >=1.3:統一各平台的行為
編譯器分發版中停止提供已棄用的構件
問題:KT-23799
組建:其他
不相容變更類型:二進制
簡短摘要:Kotlin 1.3 停止提供以下已棄用的二進制構件:
kotlin-runtime:請改用kotlin-stdlibkotlin-stdlib-jre7/8:請改用kotlin-stdlib-jdk7/8- 編譯器分發版中的
kotlin-jslib:請改用kotlin-stdlib-js棄用週期:
- 1.2.X:構件被標記為已棄用,編譯器對使用這些構件回報警告
- >=1.3:停止提供這些構件
stdlib 中的註解
問題:KT-21784
組建:kotlin-stdlib (JVM)
不相容變更類型:二進制
簡短摘要:Kotlin 1.3 從 stdlib 中移除了
org.jetbrains.annotations套件中的註解,並將其移動到隨編譯器隨附的獨立構件中:annotations-13.0.jar和mutability-annotations-compat.jar棄用週期:
- <1.3:註解隨 stdlib 構件一起隨附
- >=1.3:註解在獨立構件中隨附
