[译]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,欢迎加入咱们~~~

相关文章
相关标签/搜索