[譯]Kotlin中是應該使用序列(Sequences)仍是集合(Lists)?

翻譯說明:java

原標題: Sequences — a Pragmatic Approachandroid

原文地址: proandroiddev.com/sequences-a…git

原文做者: Tomek Polańskigithub

序列(Sequences) 是一個很棒的工具,它有一些不一樣於Android開發人員習慣的處理數據集合的方法。在我以前的文章中,我比較了各類操做集合的方式,如今我想給你介紹關於何時使用Sequences(序列),何時該使用Lists(標準集合)編程

何時使用Sequences(序列)

連接多個操做符

處理集合時性能損耗的最大緣由是循環。集合元素迭代的次數越少性能越好。咱們舉個例子:app

list
  .map { it + 1 }
  .filter { it % 2 == 0 }
  .count { it < 10 } //286 μs
複製代碼

decompile code函數

Collection<Integer> destination = new ArrayList<>(list.size());
Iterable<Integer> iterable = list;
Iterator<Integer> iterator = iterable.iterator();

while (iterator.hasNext()) {
    int it = iterator.next();
    destination.add(it + 1);
}

iterable = destination;
destination = new ArrayList<>();
iterator = iterable.iterator();

while (iterator.hasNext()) {
    int it = iterator.next();
    if (it % 2 == 0) {
        destination.add(it);
    }
}

iterable = destination;
int count = 0;
iterator = iterable.iterator();

while (iterator.hasNext()) {
     int it = iterator.next();
    if (it < 10) {
        ++count;
    }
}
return count;
複製代碼

當你反編譯上述代碼的時候,你會發現Kotlin編譯器會建立三個while循環.其實你可使用命令式編程方式利用一個循環就能實現上面相同任務的需求。不幸的是,編譯器沒法將代碼優化到這樣的程度。工具

序列(Sequences) 的祕訣在於它們是共享同一個迭代器(iterator) ---序列容許 map操做 轉換一個元素後,而後立馬能夠將這個元素傳遞給 filter操做 ,而不是像集合(lists) 同樣等待全部的元素都循環完成了map操做後,用一個新的集合存儲起來,而後又遍歷循環重新的集合取出元素完成filter操做。經過減小循環次數,該序列爲咱們提供了26%(List爲286μs,Sequence爲212μs)性能提高:post

list
  .asSequence()
  .map { it + 1 }
  .filter { it % 2 == 0 }
  .count { it < 10 } //212 μs
複製代碼

使用first{...}或者last{...}操做符

當使用接收一個預判斷的條件 first or last 方法時候,使用**序列(Sequences)**會產生一個小的性能提高,若是將它與其餘操做符結合使用,它的性能將會獲得更大的提高。性能

list
  .map { it + 1 }
  .first { it % 100 == 0 } // 232 μs
複製代碼

使用了序列(Sequences) 的版本:

list
  .asSequence()
  .map { it + 1 }
  .first { it % 100 == 0 } // 8 μs
複製代碼

經過對比咱們能夠看到有了97%的性能提高。

何時使用Lists(集合)

量級比較小的集合元素

Kotlin Lists API在處理一些小量級的集合元素(好比說少於100個)時仍然很是有效,你不該該在意它是否須要0.000007s(7μs)或0.000014s(14μs),一般不值得花了很大功夫去進行優化。

訪問索引元素

Lists(集合) 是有索引的,這就是爲何按索引訪問項目很是快而且具備恆定時間複雜度的緣由。在另外一方面,Sequences(序列) 則必須逐項進行,直到它們到達目標項目。

請注意,對於不須要知足預判斷條件的first() 或者 last()方法,它們在內部則是使用index(索引)來訪問List中的元素--這就是爲何它們相對於Sequences會更快。

返回/傳遞給其餘的函數

每次迭代Sequences(序列) 時,都會計算元素。Lists(集合) 中的元素只計算一次,而後存儲在內存中。

這就是爲何你不該該將Sequences(序列) 做爲參數傳遞給函數: 函數可能會屢次遍歷它們。在傳遞或者在整個使用List以前建議將Sequences(序列) 轉換 Lists(集合)

若是你真的想要傳遞一個Sequences(序列),你可使用constrainOnce() - 它只容許一次遍歷Sequences(序列),第二次嘗試遍歷會拋出一個異常。 不過,我不會建議這種方法,由於它使代碼難以維護。

您也可使用這個簡單的決策樹來決定選擇一個Sequences(序列) 仍是一個 Lists(集合)

若是您的應用程序處理大量數據,Sequences(序列) 將爲您帶來不錯的性能提高。不過,您不須要在代碼中更改全部用到List的地方,而是真正須要去查明影響性能的瓶頸,而後去解決它。

譯者有話說

  • 一、爲何我要翻譯這篇博客?

序列(Sequences) 能夠說是優化集合中一些操做性能的工具,它實際上和Java8中的Stream功能相似,可能有時候咱們一些初學者還不可以很好的去駕馭它。不知道何時該用序列(Sequences) 何時該用 集合(Lists),可能不少人很難發覺他們有什麼不一樣,由於咱們平時操做的數據集合量級很小,性能損耗差很少,可是一旦處於比較大數據量級,它們之間的差別將會很是明顯。然而這篇博客的原做者作過一個這樣對比,比較了序列(Sequences)、集合(Lists)、RxJava三者之間在同一個數據量級的性能對比。做者列出詳細圖表對比(詳細可見這篇博客: Declarative Kotlin: Lists, Sequences and RxJava. 因此學完在合適的時機,選擇正確操做數據集合方式很是重要,因此這是我翻譯這篇博客初衷。

  • 二、關於什麼使用序列(Sequences) 提煉幾點。

第1、數據集量級是足夠大,建議使用序列(Sequences)

第2、對數據集進行頻繁的數據操做,相似於多個操做符鏈式操做,建議使用序列(Sequences)

第3、對於使用first{},last{}建議使用序列(Sequences)。補充一下,細心的小夥伴會發現當你對一個集合使用first{},last{}操做符的時候,咱們IDE工具會提示你建議使用序列(Sequences) 代替 集合(Lists),這時候足以看出Kotlin這門語言在IDE支持方面,有得天獨厚的優點,畢竟人家Kotlin是JetBrains公司的親兒子。

  • 三、總結

關於序列(Sequences) 實際上這篇博客只是大概給出了使用序列時機,可是序列在底層實現上爲何性能會優於集合,以及序列更多細節的內容只是一筆帶過,那麼個人下篇博客將會深刻解析Kotlin中的序列,而這篇博客算是有個大概的認識。

歡迎關注Kotlin開發者聯盟,這裏有最新Kotlin技術文章,每週會不按期翻譯一篇Kotlin國外技術文章。若是你也喜歡Kotlin,歡迎加入咱們~~~

相關文章
相關標籤/搜索