騰訊視頻連接:html
v.qq.com/x/page/d093…android
Bilibili 視頻連接:git
www.bilibili.com/video/av977…github
當即執行和延遲執行的區別在於每次對集合進行轉換時,這個操做會在什麼時候真正執行。api
Collection(也稱集合) 是在每次操做時當即執行的,執行結果會存儲到一個新的集合中。做用於 Collection 的轉換操做是內聯函數。例如,map 的實現方式,能夠看到它是一個建立了新 ArrayList 的內聯函數:bash
public inline fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R> {
return mapTo(ArrayList<R>(collectionSizeOrDefault(10)), transform)
}
複製代碼
Sequence (也稱序列) 是延遲執行的,它有兩種類型: 中間操做 (intermediate) 和末端操做(terminal)。中間操做不會當即執行,它們只是被存儲起來,僅當末端操做被調用時,纔會按照順序在每一個元素上執行中間操做,而後執行末端操做。中間操做 (好比 map、distinct、groupBy 等) 會返回另外一個Sequence,而末端操做 (好比 first、toList、count 等) 則不會。jvm
Sequence 是不會保留對集合項目的引用的。它基於原始集合的迭代器 (iterator) 建立,而且保留要執行的全部中間操做的引用。ide
與在 Collection 中執行轉換操做不一樣,Sequence 執行的中間轉換不是內聯函數,由於內聯函數沒法存儲,而 Sequence 須要存儲它們。咱們能夠經過下列代碼看到像 map 這樣的中間操做是如何實現的,能夠看到轉換函數會存儲在一個新的 Sequence 實例中:函數
public fun <T, R> Sequence<T>.map(transform: (T) -> R): Sequence<R>{
return TransformingSequence(this, transform)
}
複製代碼
例如 first 這樣的末端操做,會對 Sequence 中的元素進行遍歷,直到預置條件匹配爲止。性能
public inline fun <T> Sequence<T>.first(predicate: (T) -> Boolean): T {
for (element in this) if (predicate(element)) return element
throw NoSuchElementException(「Sequence contains no element matching the predicate.」)
}
複製代碼
若是觀察 TransformingSequence 這樣的類型是如何實現的,咱們會發如今迭代器上調用 next 時,轉換存儲操做也一併被應用。
internal class TransformingIndexedSequence<T, R>
constructor(private val sequence: Sequence<T>, private val transformer: (Int, T) -> R) : Sequence<R> {
override fun iterator(): Iterator<R> = object : Iterator<R> {
…
override fun next(): R {
return transformer(checkIndexOverflow(index++), iterator.next())
}
…
}
複製代碼
不管您使用 Collection 仍是 Sequence,Kotlin 標準庫都提供了相似於 find、filter、groupBy 等一系列操做,在使用它們以前,您得確保瞭解這些操做。
Collections
Sequences
使用 Sequence 時不會去建立中間集合,因爲項目會被逐個執行,map 操做只會做用到部分輸入上。
轉換的順序
不管您使用 Collection 仍是 Sequence,轉換的順序都很重要。在上面的例子中,first 不須要先在 map 以後進行操做,由於 first 不須要 map 操做的結果就可以執行。若是咱們顛倒業務邏輯的順序,先把 first 做用到 Collection 上,再對結果執行轉換,那麼咱們只會建立一個新的對象 —— 一個黃色的正方形。當使用 Sequence 時,會避免建立兩個新對象,而當使用 Collection 時則會避免建立整個列表。
內聯和大數據集所帶來的影響
Collection 的操做使用了內聯函數,因此處理所用到的字節碼以及傳遞給它的 lambda 字節碼都會進行內聯操做。而 Sequence 不使用內聯函數,所以,它會爲每一個操做建立新的 Function 對象。
另外,Collection 會爲每一個轉換操做建立一個新的列表,而 Sequence 僅僅是保留對轉換函數的引用。
當對數據量小的 Collection 執行 1 到 2 個操做時,上面所說的差別並不會帶來什麼樣的影響,因此這種狀況下使用Collection 是沒問題的。而當列表數據很大時,中間集合的建立會很消耗資源,這種狀況下就應該使用 Sequence。
不幸的是,我不知道有什麼樣的基準測試可以幫助咱們更好地探索出具體不一樣大小的集合或者操做鏈纔會對 Collection 和 Sequence 產生影響。
綜上所述,Collection 會當即執行對數據的操做,而 Sequence 則是延遲執行。根據要處理的數據量大小,選擇最合適的一個: 數據量小,則使用 Collection,數據量大,則使用 Sequence,另外,需注意操做順序帶來的影響。
點擊這裏瞭解更多關於用 Kotlin 進行 Android 開發的相關資料