Kotlin 1.1 的新特性
Kotlin 1.1 的新特性
目錄
JavaScript
協程(實驗性的)
Kotlin 1.1的關鍵新特性是協程,它帶來了
future
/ await
、yield
以及類似的編程模式的支持。Kotlin的設計中的關鍵特性是協程執行的實現是語言庫的一部分,而不是語言的一部分,所以你不必綁定任何特定的編程範式或併發庫。
這裡,
async { …… }
啟動一個協程,當我們使用await()
時,掛起協程的執行,而執行正在等待的操作,並且在等待的操作完成時恢復(可能在不同的線程上) 。
標準庫通過
yield
和yieldAll
函數使用協程來支持惰性生成序列。在這樣的序列中,在取回每個元素之後掛起返回序列元素的代碼塊,並在請求下一個元素時恢復。這裡有一個例子:
Target platform: JVM Running on kotlin v. 1.3.11
運行上面的代碼以查看結果。隨意編輯它並再次運行!
請注意,協程目前還是一個實驗性的特性,這意味著Kotlin團隊不承諾在最終的1.1版本時保持該功能的向後兼容性。
其他語言功能
類型別名
類型別名允許你為現有類型定義備用名稱。這對於泛型類型(如集合)以及函數類型最有用。這裡有幾個例子:
Target platform: JVM Running on kotlin v. 1.3.11
已綁定的可調用引用
Target platform: JVM Running on kotlin v. 1.3.11
密封類和數據類
Kotlin 1.1 刪除了一些對Kotlin 1.0 中已存在的密封類和數據類的限制。現在你可以在同一個文件中的任何地方定義一個密封類的子類,而不只是以作為密封類嵌套類的方式。數據類現在可以擴展其他類。這可以用來友好且清晰地定義一個表達式類的層次結構:
Target platform: JVM Running on kotlin v. 1.3.11
lambda 表達式中的解構
Target platform: JVM Running on kotlin v. 1.3.11
下劃線用於未使用的參數
對於具有多個參數的lambda表達式,可以使用
_
字符替換不使用的參數的名稱:
Target platform: JVM Running on kotlin v. 1.3.11
Target platform: JVM Running on kotlin v. 1.3.11
數字字面值中的下劃線
正如在Java 8 中一樣,Kotlin 現在允許在數字字面值中使用下劃線來分隔數字分組:
Target platform: JVM Running on kotlin v. 1.3.11
對於屬性的更短語法
對於沒有自定義訪問器、或者將getter 定義為表達式主體的屬性,現在可以省略屬性的類型:
Target platform: JVM Running on kotlin v. 1.3.11
內聯屬性訪問器
Target platform: JVM Running on kotlin v. 1.3.11
你也可以將整個屬性標記為
inline
——這樣修飾符應用於兩個訪問器。局部委託屬性
Target platform: JVM Running on kotlin v. 1.3.11
委託屬性綁定的攔截
provideDelegate
方法在創建MyUI
實例期間將會為每個屬性調用,並且可以立即執行必要的驗證。泛型枚舉值訪問
現在可以用泛型的方式來對枚舉類的值進行枚舉:
Target platform: JVM Running on kotlin v. 1.3.11
對於DSL 中隱式接收者的作用域控制
在Kotlin 1.0中,傳遞給
td
的lambda表達式中的代碼可以訪問三個隱式接收者:傳遞給table
、tr
和td
的。這允許你調用在上下文中沒有意義的方法——例如在td
裡面調用tr
,從而在
中放置一個
標籤。
在Kotlin 1.1中,你可以限制這種情況,以使只有在
td
的隱式接收者上定義的方法會在傳給td
的lambda表達式中可用。你可以通過定義標記有@DslMarker
元註解的註解並將其應用於標記類的基類。
rem
操作符
標準庫
字符串到數字的轉換
在String類中有一些新的擴展,用來將它轉換為數字,而不會在無效數字上拋出異常:
String.toIntOrNull(): Int?
、String.toDoubleOrNull(): Double?
等。
還有整數轉換函數,如
Int.toString()
、String.toInt()
、String.toIntOrNull()
,每個都有一個帶有radix
參數的重載,它允許指定轉換的基數(2到36)。onEach()
onEach
是一個小、但對於集合和序列很有用的擴展函數,它允許對操作鏈中的集合/序列的每個元素執行一些操作,可能帶有副作用。對於迭代其行為像forEach
但是也進一步返回可迭代實例。對於序列它返回一個包裝序列,它在元素迭代時延遲應用給定的動作。also()、takeIf() 和takeUnless()
這些是適用於任何接收者的三個通用擴展函數。
also
就像apply
:它接受接收者、做一些動作、並返回該接收者。二者區別是在apply
內部的代碼塊中接收者是this
,而在also
內部的代碼塊中是it
(並且如果你想的話,你可以給它另一個名字)。當你不想掩蓋來自外部作用域的this
時這很方便:
Target platform: JVM Running on kotlin v. 1.3.11
takeIf
就像單個值的filter
。它檢查接收者是否滿足該謂詞,並在滿足時返回該接收者否則不滿足時返回null
。結合elvis-操作符和及早返回,它允許編寫如下結構:
Target platform: JVM Running on kotlin v. 1.3.11
takeUnless
與takeIf
相同,只是它採用了反向謂詞。當它不滿足謂詞時返回接收者,否則返回null
。因此,上面的示例之一可以用takeUnless
重寫如下:
當你有一個可調用的引用而不是lambda 時,使用也很方便:
Target platform: JVM Running on kotlin v. 1.3.11
groupingBy()
此API可以用於按照鍵對集合進行分組,並同時折疊每個組。例如,它可以用於計算文本中字符的頻率:
Target platform: JVM Running on kotlin v. 1.3.11
Map.toMap() 和Map.toMutableMap()
這倆函數可以用來簡易複製映射:
Map.minus(key)
運算符
plus
提供了一種將鍵值對添加到只讀映射中以生成新映射的方法,但是沒有一種簡單的方法來做相反的操作:從映射中刪除一個鍵採用不那麼直接的方式如Map.filter()
或Map.filterKeys()
。現在運算符minus
填補了這個空白。有4個可用的重載:用於刪除單個鍵、鍵的集合、鍵的序列和鍵的數組。
Target platform: JVM Running on kotlin v. 1.3.11
minOf() 和maxOf()
這些函數可用於查找兩個或三個給定值中的最小和最大值,其中值是原生數字或
Comparable
對象。每個函數還有一個重載,它接受一個額外的Comparator
實例,如果你想比較自身不可比的對象的話。
Target platform: JVM Running on kotlin v. 1.3.11
類似數組的列表實例化函數
類似於
Array
構造函數,現在有創建List
和MutableList
實例的函數,並通過調用lambda表達式來初始化每個元素:
Target platform: JVM Running on kotlin v. 1.3.11
Map.getValue()
Map
上的這個擴展函數返回一個與給定鍵相對應的現有值,或者拋出一個異常,提示找不到該鍵。如果該映射是用withDefault
生成的,這個函數將返回默認值,而不是拋異常。
Target platform: JVM Running on kotlin v. 1.3.11
抽象集合
這些抽像類可以在實現Kotlin集合類時用作基類。對於實現只讀集合,有
AbstractCollection
、AbstractList
、AbstractSet
和AbstractMap
,而對於可變集合,有AbstractMutableCollection
、AbstractMutableList
、AbstractMutableSet
和AbstractMutableMap
。在JVM上,這些抽象可變集合從JDK的抽象集合繼承了大部分的功能。數組處理函數
標準庫現在提供了一組用於逐個元素操作數組的函數:比較(
contentEquals
和contentDeepEquals
),哈希碼計算(contentHashCode
和contentDeepHashCode
),以及轉換成一個字符串(contentToString
和contentDeepToString
)。它們都支持JVM (它們作為java.util.Arrays
中的相應函數的別名)和JS(在Kotlin標準庫中提供實現)。
Target platform: JVM Running on kotlin v. 1.3.11
JVM 後端
Java 8 字節碼支持
Kotlin現在可以選擇生成Java 8字節碼(命令行選項
-jvm-target 1.8
或者Ant/Maven/Gradle中的相應選項)。目前這並不改變字節碼的語義(特別是,接口和lambda表達式中的默認方法的生成與Kotlin 1.0中完全一樣),但我們計劃在以後進一步使用它。Java 8 標準庫支持
現在有支持在Java 7和8中新添加的JDK API的標準庫的獨立版本。如果你需要訪問新的API,請使用
kotlin-stdlib-jre7
和kotlin-stdlib-jre8
maven構件,而不是標準的kotlin-stdlib
。這些構件是在kotlin-stdlib
之上的微小擴展,它們將它作為傳遞依賴項帶到項目中。字節碼中的參數名
Kotlin現在支持在字節碼中存儲參數名。這可以使用命令行選項
-java-parameters
啟用。常量內聯
編譯器現在將
const val
屬性的值內聯到使用它們的位置。可變閉包變量
用於在lambda表達式中捕獲可變閉包變量的裝箱類不再具有volatile字段。此更改提高了性能,但在一些罕見的使用情況下可能導致新的競爭條件。如果受此影響,你需要提供自己的同步機制來訪問變量。
javax.scripting 支持
kotlin.reflect.full
為Java 9支持準備,在
kotlin-reflect.jar
庫中的擴展函數和屬性已移動到kotlin.reflect.full
包中。舊包(kotlin.reflect
)中的名稱已棄用,將在Kotlin 1.2中刪除。請注意,核心反射接口(如KClass
)是Kotlin標準庫(而不是kotlin-reflect
)的一部分,不受移動影響。JavaScript 後端
統一的標準庫
Kotlin標準庫的大部分目前可以從代碼編譯成JavaScript來使用。特別是,關鍵類如集合(
ArrayList
、HashMap
等)、異常(IllegalArgumentException
等)以及其他幾個關鍵類(StringBuilder
、Comparator
)現在都定義在kotlin
包下。在JVM平台上,一些名稱是相應JDK類的類型別名,而在JS平台上,這些類在Kotlin標準庫中實現。更好的代碼生成
JavaScript 後端現在生成更加可靜態檢查的代碼,這對JS 代碼處理工具(如minifiers、 optimisers、 linters 等)更加友好。
external
修飾符
如果你需要以類型安全的方式在Kotlin中訪問JavaScript實現的類,你可以使用
external
修飾符寫一個Kotlin聲明。(在Kotlin 1.0中,使用了@native
註解。)與JVM目標平台不同,JS平台允許對類和屬性使用external修飾符。例如,可以按以下方式聲明DOM Node
類:改進的導入處理
現在可以更精確地描述應該從JavaScript模塊導入的聲明。如果在外部聲明上添加
@JsModule("<模块名>")
註解,它會在編譯期間正確導入到模塊系統(CommonJS或AMD)。例如,使用CommonJS,該聲明會通過require(……)
函數導入。此外,如果要將聲明作為模塊或全局JavaScript對象導入,可以使用@JsNonModule
註解。
例如,以下是將JQuery 導入Kotlin 模塊的方法:
在這種情況下,JQuery將作為名為
jquery
的模塊導入。或者,它可以用作$-對象,這取決於Kotlin編譯器配置使用哪個模塊系統。
你可以在應用程序中使用如下所示的這些聲明: