- Kotlin入門筆記一:方法、變量、類
- Kotlin入門筆記二:when、for、in
- Kotlin入門筆記三:可空類型
- Kotlin入門筆記四:集合
- Kotlin入門筆記五:可見修飾符
- Kotlin入門筆記六:Lambda語法
- Kotlin入門筆記七:Lambda之引用
- Kotlin入門筆記八:Lambda和序列
序列(Sequence):
首先我們來了解一下什麼是序列,序列其實類似集合的一個接口,只不過它的操作都是惰性集合操作,所有在集合上的操作符都適用於序列。下面我們來看看如何生成一個序列:
// 列表和序列
val list = listOf(1,2,3,4)
println(list)
println(list.asSequence())
輸出:
[1, 2, 3, 4]
kotlin.collections.CollectionsKt___CollectionsKt$asSequence$$inlined$Sequence$1@13fee20c
生成一個序列的一種方式就是通過list.asSequence()
,但是我麼在輸出日誌中才發現它的輸出其實沒有內容,那麼如果要查看序列的內容可以將它轉換爲集合。
println(list.asSequence().toList())
輸出:
[1, 2, 3, 4]
這樣我們接可以看到結果。
序列的優勢:
那麼有了集合這麼好用的東西,我們爲什麼要使用序列呢?接下來我們看一個小小的例子:
我們拿到了100W條用戶數據,需要將這些用戶年齡是偶數的姓名全打印出來。如果不使用序列,我們的做法爲:
println(userList
.filter { it.age % 2 != 0 }
.map { User::age })
這個寫法肯定沒有錯,對於少量數據來說也沒什麼影響,可是這裏大家注意,是100W條數據,我們可以點擊map
和filter
查看源碼,每一步操作都會生成另外一個集合,對於大量數據來說,這可是一筆很大的消耗,在性能上是很不理想的。這時候就到了我們序列大顯身手的時候了,來看看序列是如何減少性能消耗的:
println(userList.asSequence()
.filter { it.age % 2 != 0 }
.map { User::age }
.toList())
這裏我們先將集合轉換爲序列,在最後的操作中才將序列轉換爲集合的。序列在中間操作都是惰性的,不會創建額外的集合來保存過程中產生的中間結果,使用序列可以高效的對集合元素執行鏈式操作。
序列操作的執行過程:
序列操作分爲兩個過程:中間操作、末端操作。中間操作全部都是惰性操作,如果沒有執行末端操作,中間操作都會被延期。我們來看以下代碼加深理解:
val list = listOf(1, 2, 3, 4)
list.asSequence().filter { print(it);it > 2 }
list.asSequence().filter { print(it);it > 2 }.toList()
我們在中間操作filter()
打印集合的元素,但是在日誌中會發現,不加toList()
的是不會有任何結果的,只有加上了toList()
纔會執行print(it)
操作,也就證明了爲什麼說中間操作是惰性的,在沒有末端操作的時候,中間操作會被延期。
注意:末端操作的定義可以理解爲:只要不是在這個操作後生成的對象依舊是序列就屬於末端操作。
序列和集合的執行順序:
對於一個鏈式操作,我們可以先大致猜一下,序列和集合的執行順序是否是一樣?
我們來通過一個簡單的例子理解下:
val list = listOf(1, 2, 3, 4)
list.map { print("map($it) "); it * it }
.filter { print("filter($it )"); it > 5 }
println()
list.asSequence()
.map { print("map($it) ");it * it }
.filter { print("filter($it) ");it > 5 }
.toList()
這個例子很簡單,map
之後filter
,每一步操作我們都做輸出處理,結果如下:
map(1) map(2) map(3) map(4) filter(1 )filter(4 )filter(9 )filter(16 )
map(1) filter(1) map(2) filter(4) map(3) filter(9) map(4) filter(16)
從結果我們一眼就能看出,集合和序列在鏈式的執行順序是不一樣的,集合在鏈式中先處理完第一步所有的元素,再處理第二步所有的元素,以此類推。而序列不是,序列是對每個元素做鏈式操作,只有第一個元素執行完所有的鏈式操作,才執行第二個元素的鏈式操作。
千萬不要小瞧這個區別,它將爲我們在大量數據處理上帶來很大的優化和便捷。比如:
val list = listOf(1, 2, 3, 4,·······)
list.map { it * it }
.find { it > 5 }
list.asSequence()
.map { it * it }
.find { it > 5 }
這裏我們想象集合中有大量的數據,集合和序列的執行流程如下:
從圖中我們可以得出這樣一個結論,在
map()
中間操作的時候,集合需要將每一個元素都執行一次,但是序列在找到滿足find { it > 5 }
的元素時,map()
操作將不會繼續執行,可以減少不需要的大量操作。這就是序列的另一大優勢。
總結:
無論是在集合還是序列的鏈式操作中,都需要大量的使用到Lambda,熟練的使用Lambda結合集合和序列的轉換將在日常開發中得到一種很完美的編碼體驗,希望大家一定要熟悉的理解序列和集合之間聯繫和區別。
下一份筆記將爲大家帶來Kotlin版的MVP+OKhttp3+Retrofit+RxJava的項目基本框架
寫在最後
每個人不是天生就強大,你若不努力,如何證明自己,加油!
Thank You!
--Taonce