Effective Kotlin中文版
  • ReadMe
  • 前言
  • 第一部分:良好的代码
    • 第一章:安全性
      • 第1条:限制可变性
      • 第2条:最小化变量的作用域
      • 第3条:尽可能消除平台类型
      • 第4条: 不要暴露需要推断的类型
      • 第5条:指明你期望的参数和状态
      • 第 6 条: 优先使用标准错误,而不是自定错误
      • 第7条:当返回结果可能缺失时,优先使 null 或 Failure
      • 第8条:妥善处理空值
      • 第9条: 使用 use 来关闭资源
      • 第10条:编写单元测试
    • 第二章:可读性
      • 第11条:为了可读性设计代码
      • 第12条:操作符的行为应该与其名称一致
      • 第13条:避免返回或操作 Unit?
      • 第14条: 在变量不清晰时指定其类型
      • 第15条:考虑显式引用接收者
      • 第16:属性应该代表状态,而非行为
      • 第17条:考虑使用具名参数
      • 第18条:遵守编程惯例
  • 第二部分:良好的设计
    • 第三章:可重用性
      • 第19条:不要重复知识
      • 第20条:不要重复实现常用算法
      • 第21条 使用属性代理来提取公共的属性模式
      • 第22条:当实现公共算法时使用泛型
      • 第23条:避免隐藏类型参数
      • 第24条:在使用泛型时考虑型变
      • 第25条:在不同的平台上提取公共模块进行重用
    • 第四章:抽象设计
      • 第26条:每个方法都应该基于单一的抽象级别而编写
      • 第27条:使用抽象来保护代码不受更改
      • 第28条:指定 Api 的稳定性
      • 第29条:考虑包装扩展 API
      • 第30条:最小化元素的可见性
      • 第31条:用文档定义合约
      • 第32条:遵守抽象合约
    • 第五章:对象的创建
      • 第33条:考虑使用工厂方法代替构造函数
      • 第34条:考虑带命名默认参数的主构造函数
      • 第35条:考虑为复杂的对象创建定义 DSL
    • 第六章:类的设计
      • 第36条:组合优于继承
      • 第37条:使用数据修饰符来表示一组数据
      • 第38条:使用函数类型而不是接口来传递操作和行为
      • 第39条:类层次结构优于标签类
      • 第40条:遵守 equals 的合约
      • 第41条:遵守 hashCode 的合约
      • 第42条:遵守 compareTo 的合约
      • 第43条: 考虑将 API 的非必要部分提取到扩展函数中
      • 第44条:避免在成员中定义扩展
  • 第三部分:性能
    • 第七章:让开发成本更低
      • 第45条:避免不必要的对象创建
      • 第46条:给高阶函数使用 inline 修饰符
      • 第47条:考虑使用内联类
      • 第48条:消除过时的对象引用
    • 第八章:高效的集合处理
      • 第49条:在具有多个处理步骤的大型集合上,优先使用 Sequence
      • 第50条:限制操作步骤的数量
      • 第51条:性能关键处考虑使用原语的数组
      • 第52条:考虑使用可变集合
Powered by GitBook
On this page
  1. 第三部分:性能

第八章:高效的集合处理

集合是编程中最重要的概念之一。在 iOS 中,最重要的视图元素之一 ——UICollectionView,被设计用来表示一个集合。同样,在 Android 中,很难想象一个没有 RecyclerView 或 ListView 的应用程序。当需要编写带有新闻资讯的页面时,你将会拥有一个新闻列表,每个新闻信息可能都有一个作者列表和一个标签列表;当你创建一个在线商店时,会从产品列表开始,这些产品可能有分类列表和一个不同变体的列表;当用户购买时,它们可能有购物车,里面是产品及其数量的集合;然后他们需要从一系列的送货方式和付款方式中做出选择。在某些语言中,String 只是许多字符的集合,集合在编程中无处不在!只要着眼于你当前的应用程序,很快就会看到大量的集合。

这一事实也可以反映在编程语言中,大多数现代语言都有一些集合的声明用法:

// Python
primes = [2, 3, 5, 7, 13]
// Swift
let primes = [2, 3, 5, 7, 13]

良好的集合处理是函数式编程语言的标志性功能。 Lisp 语言的名字就代表了“列表处理(list processing)”。大多数现代语言都对集合处理提供了良好的支持,这些语言也包括了 Kotlin, 它具有一组最强大的集合处理工具。来看看下面的集合处理:

val visibleNews = mutableListOf<News>()
for (n in news) {
    if(n.visible) {
        visibleNews.add(n)
    }
}

Collections.sort(visibleNews,
    { n1, n2 -> n2.publishedAt - n1.publishedAt })
val newsItemAdapters = mutableListOf<NewsItemAdapter>()
for (n in visibleNews) {
    newsItemAdapters.add(NewsItemAdapter(n))
}

在 Kotlin 中,上面的代码可以用下面的代码来替代:

val newsItemAdapters = news
    .filter { it.visible }
    .sortedByDescending { it.publishedAt }
    .map(::NewsItemAdapter)

这样的语法不仅更短,而且可读性更强。每一步都对元素列表进行具体的转换。以下是上述处理的可视化过程:

上述示例的性能看似非常相似。但事实并非总是那么简单。 Kotlin 有很多集合处理方法,我们有各种方式不同但效果相同的函数来处理列表。例如,下面的处理实现具有相同的结果,但性能差异迥异:

fun productsListProcessing(): String {
    return clientsList
        .filter { it.adult }
        .flatMap { it.products }
        .filter { it.bought }
        .map { it.price }
        .filterNotNull()
        .map { "$$it" }
        .joinToString(separator = " + ")
}

fun productsSequenceProcessing(): String {
    return clientsList.asSequence()
        .filter { it.adult }
        .flatMap { it.products.asSequence() }
        .filter { it.bought }
        .mapNotNull { it.price }
        .joinToString(separator = " + ") { "$$it" }
}

集合处理的优化不仅仅是一个智力难题。

集合处理极其重要,在大型系统中,性能通常是至关重要的。这就是为什么提高程序性能往往是很关键的,特别是当我们进行后端应用程序开发或数据分析时。但是,当我们实现前端客户端时,我们也会面临集合的处理,这也会限制应用程序的性能。作为一名顾问,在看过很多项目后,我的经验是,我在很多不同的地方看到了一次又一次的集合处理,这不是一件容易被忽略的事情。

好消息是,集合处理优化不难掌握,有一些规则和少数事情需要去记住,但事实上任何人都可以高效的完成。这就是我们这一章要学习的内容。

Previous第48条:消除过时的对象引用Next第49条:在具有多个处理步骤的大型集合上,优先使用 Sequence

Last updated 2 years ago