以前探究集合的函數式Api時發現,這些函數都會遍歷集合而且提前建立新集合,每一步的中間結果會被存儲在新集合中。當數據量很大時,調用十分的低效。android
fun main(args: Array<String>) {
val list = (1..10).toList()
list.filter {
it % 2 == 0
}.map {
it * it
}.forEach {
println(it)
}
}
複製代碼
序列對每一個元素逐個執行全部處理步驟,能夠避免構建中間變量,提升整個集合處理鏈的性能。序列也稱爲惰性集合,序列與Java8中的Stream很像,序列是Kotlin對流這種概念提供的實現。設計模式
Kotlin惰性集合操做的入口是 Sequence
接口。該接口只有 iterator
方法,用來從序列中獲取值。bash
public interface Sequence<out T> {
public operator fun iterator(): Iterator<T>
}
複製代碼
建立序列有四種方式:ide
sequenceOf()
,將元素做爲其參數。(相似建立集合的那一堆頂層函數,如listOf)val numbers= sequenceOf(1,2,3,4,5,6,7,8,9,10)
複製代碼
asSequence()
將集合轉換爲序列。(經常使用)val numbers = (1..10).toList().asSequence()
複製代碼
generateSequence()
。給定一個初識的元素,並提供函數計算下一個元素。該函數會一直生成序列的元素,直到函數實參返回null爲止。若是函數實參不返回null,則該序列將是一個無限序列:val numbers = generateSequence(6){
it + 2
}
複製代碼
使用generateSequence()
提供有限序列:函數
val numbers = generateSequence(6){
if (it < 10)
it + 2
else
null
}
複製代碼
sequence()
函數.該函數接收一個函數類型爲 SequenceScope<T>.() -> Unit
的實參。能夠在傳遞給sequence()
函數的lambda表達式中使用SequenceScope
對象的 yield() 和 yieldAll() 添加序列元素。yield()用於添加單個序列元素; yieldAll()用於將列表或序列中的元素轉化爲新序列的元素。val numbers = sequence{
yield(1)
yieldAll(listOf(2,3))
yieldAll(setOf(4,5))
yieldAll(generateSequence(6){
if (it < 10)
it + 1
else
null
})
}
複製代碼
序列同樣能夠像集合同樣調用函數式Api,但序列的操做分爲兩大類:中間操做和終端操做。post
中間操做的定義:中間操做始終是惰性的,中間操做返回的是另外一個序列。性能
能夠經過函數的返回信息,判斷是否爲中間操做:ui
//filter函數,返回Sequence<T>,中間操做。
//注意這是一個帶Sequence<T>接收者的函數類型參數!!
public fun <T> Sequence<T>.filter(predicate: (T) -> Boolean): Sequence<T> {
return FilteringSequence(this, true, predicate)
}
//map函數,返回Sequence<T>,中間操做
//注意這是一個帶Sequence<T>接收者的函數類型參數!!
public fun <T, R> Sequence<T>.map(transform: (T) -> R): Sequence<R> {
return TransformingSequence(this, transform)
}
複製代碼
惰性怎麼理解呢?執行如下例子:this
val list = (1..10).toList()
list.asSequence()
.filter {
println("filter $it")
it % 2 == 0
}.map {
println("map $it")
it * it
}
複製代碼
末端操做定義:觸發執行全部的延期計算(指中間操做),並返回一個結果,結果多是集合、數字等。spa
//forEach函數,返回值不是序列,末端操做
//注意這是一個帶Sequence<T>接收者的函數類型參數!
public inline fun <T> Sequence<T>.forEach(action: (T) -> Unit): Unit {
for (element in this) action(element)
}
//count函數,返回值不是序列,末端操做
//注意這是一個帶Sequence<T>接收者的函數類型參數!
public inline fun <T> Sequence<T>.count(predicate: (T) -> Boolean): Int {
var count = 0
for (element in this) if (predicate(element)) checkCountOverflow(++count)
return count
}
複製代碼
估計不少小夥伴應該和我同樣,很好奇爲何中間操做是惰性的?想要獲得答案,那就只能去查看源碼進行分析了,先看asSequence():
public fun <T> Iterable<T>.asSequence(): Sequence<T> {
return Sequence { this.iterator() }
}
public inline fun <T> Sequence(crossinline iterator: () -> Iterator<T>): Sequence<T> = object : Sequence<T> {
override fun iterator(): Iterator<T> = iterator()
}
複製代碼
asSequence()函數會建立一個匿名的Sequence匿名類對象,並將集合的迭代器存儲起來,做爲本身iterator()方法的返回值。
(能夠直接跳過代碼,看結果)
#filter函數
public fun <T> Sequence<T>.filter(predicate: (T) -> Boolean): Sequence<T> {
//返回一個FilteringSequence對象
return FilteringSequence(this, true, predicate)
}
internal class FilteringSequence<T>(
private val sequence: Sequence<T>,
private val sendWhen: Boolean = true,
private val predicate: (T) -> Boolean
) : Sequence<T> {
override fun iterator(): Iterator<T> = object : Iterator<T> {
//獲取上一個序列的迭代器
val iterator = sequence.iterator()
// -1 for unknown, 0 for done, 1 for continue
var nextState: Int = -1
var nextItem: T? = null
//計算該中間操做的實現(簡單說就是在)
private fun calcNext() {
while (iterator.hasNext()) {
val item = iterator.next()
//執行謂詞lambda,判斷是否符合條件
if (predicate(item) == sendWhen) {
//符合條件則獲取元素
nextItem = item
//並修改狀態
nextState = 1
return
}
}
nextState = 0
}
override fun next(): T {
//檢查機制
if (nextState == -1)
calcNext()
if (nextState == 0)
throw NoSuchElementException()
//獲取值,並將狀態重置
val result = nextItem
nextItem = null
nextState = -1
@Suppress("UNCHECKED_CAST")
//返回值
return result as T
}
override fun hasNext(): Boolean {
//在上一個序列的迭代器的基礎上,進行謂詞運算,判斷是否有下一個
if (nextState == -1)
calcNext()
return nextState == 1
}
}
}
複製代碼
#map函數
public fun <T, R> Sequence<T>.map(transform: (T) -> R): Sequence<R> {
return TransformingSequence(this, transform)
}
internal class TransformingSequence<T, R>
constructor(private val sequence: Sequence<T>, private val transformer: (T) -> R) : Sequence<R> {
override fun iterator(): Iterator<R> = object : Iterator<R> {
//獲取上一個序列的迭代器
val iterator = sequence.iterator()
override fun next(): R {
//用函數類型參數進行運算,返回值
return transformer(iterator.next())
}
override fun hasNext(): Boolean {
//沿用上一個序列的迭代器的hasNext()函數
return iterator.hasNext()
}
}
internal fun <E> flatten(iterator: (R) -> Iterator<E>): Sequence<E> {
return FlatteningSequence<T, R, E>(sequence, transformer, iterator)
}
}
複製代碼
結合其餘中間操做的代碼獲得的結果是:
(能夠直接跳過代碼,看結果)
#forEach函數
public inline fun <T> Sequence<T>.forEach(action: (T) -> Unit): Unit {
//迭代進行(注意該this,是指最後一箇中端操做返回的Sequence對象)
for (element in this)
action(element)
}
複製代碼
#count函數
public inline fun <T> Sequence<T>.count(predicate: (T) -> Boolean): Int {
var count = 0
//迭代進行(注意該this,是指最後一箇中端操做返回的Sequence對象)
for (element in this)
if (predicate(element))
checkCountOverflow(++count)
return count
}
複製代碼
結合其餘末端操做的代碼獲得的結果是:
總體流程以下所示:
若是在Java的角度上看,就更好理解了。先看一波反編譯代碼:
public static final void main(@NotNull String[] args) {
List list = CollectionsKt.listOf(new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
Sequence $this$forEach$iv = SequencesKt.map(SequencesKt.filter(CollectionsKt.asSequence((Iterable)list), (Function1)null.INSTANCE), (Function1)null.INSTANCE);
int $i$f$forEach = false;
Iterator var4 = $this$forEach$iv.iterator();
while(var4.hasNext()) {
Object element$iv = var4.next();
int it = ((Number)element$iv).intValue();
int var7 = false;
boolean var8 = false;
System.out.println(it);
}
}
複製代碼
提取重點代碼(1):
//(1)將中間操做對呀的Sequence實例嵌套建立,獲得最後一箇中間操做的Sequence對象
Sequence $this$forEach$iv = SequencesKt.map(SequencesKt.filter(CollectionsKt.asSequence((Iterable)list), (Function1)null.INSTANCE), (Function1)null.INSTANCE);
複製代碼
將這行代碼簡化:
Sequence listToSequence = CollectionsKt.asSequence((Iterable)list)
Sequence filterSequence = SequencesKt.filter(listToSequence,(Function1)null.INSTANCE)
Sequence mapSequence = SequencesKt.map(filterSequence,,(Function1)null.INSTANCE)
Sequence $this$forEach$iv = mapSequence
複製代碼
能夠看到,各個中間操做都會產生的Sequence對象,都按照其調用的順序進行嵌套,最後獲得最後一箇中間操做的Sequence對象。
提取重點代碼(2):
//獲取最後一箇中間操做的Sequence對象
Iterator var4 = $this$forEach$iv.iterator();
//末端操做迭代迭代器,調用迭代器的next()方法時,將按照中間操做嵌套的瞬間執行中間操做對應的迭代器next方法,獲得中間操做的返回值
//。最後一箇中間操做的返回值交由末端操做處理
while(var4.hasNext()) {
Object element$iv = var4.next();
//..
}
複製代碼
末端操做的for循環會變成while循環,但仍是依據迭代器進行迭代。迭代過程當中不斷調用各個中間操做的迭代器,執行中間操做,最後將中間操做獲得的值交由末端操做進行處理。
Kotlin的序列使用裝飾設計模式,對集合轉換的匿名Sequence對象進行動態擴展。所謂裝飾設計模式就是在不繼承的狀況下,使類變得更強大(例如Java的I/O流)。最後在末端操做中調用Sequence的迭代器進行迭代,觸發中間操做,並獲取其返回值進行處理並輸出。