序文
この記事では、シーケンス(シーケンス)にKotlinの概念と使用を紹介し、収集チェーンへの呼び出しのパフォーマンスを最適化するために、操作の不活性セットの原理を説明します。
ディレクトリ
シーケンス(シーケンス)
コンセプト
Kotlinがチェーンのオペレータコールを設定し使用する場合、例えば、地図やフィルタは、例えば、次の例としての中間収集機能、ユーザセット内の選択されたマップおよびフィルタ部材男性の性別の使用中に作成され、結果はコレクション。
users.map(User :: sex)
.filter {it.sex.equals("male")}
配列の使用
使用順序は非常に簡単で、単にセット()関数の後に再びasSeqenceを追加することができます
users.asSequence()
.map(User :: sex)
.filter {it.sex.equals("male")}
ここでは、以下の詳細なユーザー::ユーザーが参照の一員であるという概念を、スポット
メンバ参照(メンバー参照)
コンセプト
あなたの基準部材は、簡単にダブルコロンがクラスで参照される前に、二重のコロンは、プロパティやメソッドの名前を返す必要がある以下に示します。このメンバーは、対応するクラスのプロパティやメソッドを含むクラスのメンバを呼び出すことができますセックスはユーザーメンバー属性が返されます。
User :: sex
基準部材を容易男性性別を見つけるために変数または例えば上記の例のような他の機能に割り当てることができ、以下のように、それは、やや複雑で書くことができます。
users.map(user : User -> user.sex)
.filter {it.sex.equals("male")}
目に見えるメンバーは、より読みやすい文言を引用しました。
トークシーケンス
さんが導入された配列を戻りましょう。上述のマップやフィルタを使用する場合、ソースリスト場合、問題を引き起こす内部機能のセットの途中で作成され、それは、特に、多素子のユーザーで、コレクションは非常に非効率的になるであろう連鎖、作成理由それ以上の中間のコレクション。asSequence()メソッドのシーケンスであると設定された第1の処理により変換された場合、マップおよびフィルタ操作、非常に効率的になるであろう。不適切に使用した場合、設定された一連の操作を使用しているかどうか、いくつかの前提条件があり、それは、パフォーマンスの低下の原因となります。ここで使用シナリオを要約:
パフォーマンス・テスト・シーケンス
上文提到,是否使用序列的条件之一是处理大量数据,那么这个阈值究竟是多少?下面来进行一个性能测试,构造一个商品列表,其中每个商品包含商品名和价格两个属性,现在要求出对每个商品的价格加价 100 后,价格为奇数 的商品的个数,这里用到了 count() 方法,作用是求得集合内满足 count 条件的元素的个数,代码如下:
/**
* 商品类
*/
data class Commodity(var name: String, var price: String)
import java.util.*
fun main(args: Array<String>) {
val commodityList = ArrayList<Commodity>()
for (i in 0..1000000) {
val goods = Commodity("商品 $i", i * 5)
commodityList.add(goods)
}
val startTime = System.currentTimeMillis()
commodityList
.asSequence() // 使用此函数代表使用 Kotlin 序列功能
.map { it.price + 100 }
.count { it % 2 != 0 }
println("consume time is ${System.currentTimeMillis() - startTime} ms")
}
测试结果折线图如下,其中横坐标为集合内元素的个数,纵坐标为代码执行时间,橙色线代表未使用序列,蓝色线代表使用序列:
表格对比如下:
由图可得出如下结论:
- 上文提到的阈值大致为「一百万」个元素,大于该阈值时,使用序列大致能带来 90 % 的性能提升
- 在小于「十万」个元素时,使用序列反而会造成性能下降
为什么序列会提高集合操作的性能?
- 序列对集合的操作是惰性的。
- 不需要额外的创建中间集合保存链式操作的中间结果
对于第一点,惰性这个词可能给人带来迷惑,这和使用序列后,集合的计算方式有关,下面来介绍这一点,在下面这个例子中,你需要在一个整型数据集合,将每个数乘以 2 ,并找出集合中小于 10 的第一个元素。
var result = listOf(2,4,6,8,10).asSequence
.map(it * 2)
.find(it > 10)
find() 方法的作用是在集合中查找满足条件的第一个元素,并返回查找到的值。下图是 Kotlin 使用序列进行处理
由图可知,所谓惰性,就是在使用 map 或 filter 等操作符的时候,在代码的执行顺序上,不会优先遍历所有的集合,即偷个懒,先对集合中第一个元素进行 map 和 filter, 然后对该元素执行 find 操作,发现满足 find 的条件,就立刻返回结果,由此可见,在有 map 和 find 或 last 等操作符组合时,序列的性能优化能发生最大的作用。
小结
- 在进行集合操作时,使用序列操作符,可以降低集合操作的时间和占用的空间,降低时间的原因是惰性操作,降低空间占用的原因是序列在执行操作时不会创建中间集合。
- 序列操作虽好,但也要视业务场景决定是否使用,否则反而会降低效率。