作为Java开发人员,维护糟糕的遗留代码、解释晦涩的注释、反复编写相同的样板文件可能会让编程失去乐趣。《Kotlin编程之美》讲述用Kotlin编写易于理解、易于维护、安全的程序的方法和技巧。在本书中,经验丰富的工程师皮埃尔-伊夫斯?索蒙特将以全新的、以函数式编程的视角来处理常见的编程挑战,并用示例深入讲解如何正确处理错误和数据、如何管理状态以及如何利用惰性。
《Kotlin编程之美》的内容包括编程功能、处理可选数据、安全处理错误和异常以及处理和共享状态突变等。《Kotlin编程之美》的读者对象为中级Java或Kotlin开发人员、高等院校计算机相关专业学生以及对安全编程感兴趣的工程技术人员等。
目 录
封 面
译者序
致 谢
前 言
关于本书
关于读者
关于封面插图
第1章 让程序更安全
1.1 编程陷阱
1.1.1 安全的处理作用
1.1.2 用引用透明性使程序更安全
1.2 安全编程的好处
1.2.1 使用替换模型对程序进行推理
1.2.2 应用安全原则的简单示例
1.2.3 将抽象推向极限
1.3 本章小结
第2章 Kotlin中的函数式编程:概述
2.1 Kotlin中的字段和变量
2.1.1 省略类型以简化
2.1.2 使用可变字段
2.1.3 理解延迟初始化
2.2 Kotlin中的类和接口
2.2.1 使代码更加简洁
2.2.2 实现接口或扩展类
2.2.3 实例化一个类
2.2.4 重载属性构造函数
2.2.5 创建equals和hashCode方法
2.2.6 解构数据对象
2.2.7 在Kotlin中实现静态成员
2.2.8 使用单例模式
2.2.9 防止工具类实例化
2.3 Kotlin没有原语
2.4 Kotlin的两种集合类型
2.5 Kotlin的包
2.6 Kotlin的可见性
2.7 Kotlin中的函数
2.7.1 函数声明
2.7.2 使用局部函数
2.7.3 覆盖函数
2.7.4 使用扩展函数
2.7.5 使用lamdba表达式
2.8 Kotlin中的null
2.8.1 处理可空类型
2.8.2 Elvis和默认值
2.9 程序流程和控制结构
2.9.1 使用条件选择器
2.9.2 使用多条件选择器
2.9.3 使用循环
2.10 Kotlin的未检查异常
2.11 自动关闭资源
2.12 Kotlin的智能转换
2.13 相等性VS一致性
2.14 字符串插值
2.15 多行字符串
2.16 型变:参数化类型和子类型
2.16.1 为什么型变是一个潜在的问题
2.16.2 何时使用协变以及何时使用逆变
2.16.3 声明端型变与使用端型变
2.17 本章小结
第3章 用函数编程
3.1 函数是什么?
3.1.1 理解两个函数集之间的关系
3.1.2 Kotlin中反函数概述
3.1.3 处理偏函数
3.1.4 理解函数复合
3.1.5 使用多参数函数
3.1.6 柯里化函数
3.1.7 使用偏应用函数
3.1.8 没有作用的函数
3.2 Kotlin中的函数
3.2.1 将函数理解为数据
3.2.2 将数据理解为函数
3.2.3 使用对象构造函数作为函数
3.2.4 使用Kotlin的fun函数
3.2.5 使用对象表示法和函数表示法
3.2.6 使用值函数
3.2.7 使用函数引用
3.2.8 复合函数
3.2.9 重用函数
3.3 高级函数特征
3.3.1 多参数函数如何?
3.3.2 应用柯里化函数
3.3.3 实现高阶函数
3.3.4 创建多态高阶函数
3.3.5 使用匿名函数
3.3.6 定义局部函数
3.3.7 实现闭包
3.3.8 应用偏函数和自动柯里化
3.3.9 切换偏应用函数的参数
3.3.10 声明单位函数
3.3.11 使用正确的类型
3.4 本章小结
第4章 递归、尾递归和记忆化
4.1 共递归与递归
4.1.1 实现共递归
4.1.2 实现递归
4.1.3 区分递归函数和共递归函数
4.1.4 选择递归或尾递归
4.2 尾调用消除
4.2.1 使用尾调用消除
4.2.2 从循环切换到共递归
4.2.3 使用递归值函数
4.3 递归函数和列表
4.3.1 使用双递归函数
4.3.2 对列表抽象递归
4.3.3 反转列表
4.3.4 构建共递归列表
4.3.5 严格的后果
4.4 记忆化
4.4.1 在基于循环的编程中使用记忆化
4.4.2 在递归函数中使用记忆化
4.4.3 使用隐式记忆化
4.4.4 使用自动记忆化
4.4.5 实现多参数函数的记忆化
4.5 记忆函数纯吗?
4.6 本章小结
第5章 用列表处理数据
5.1 如何对数据集合进行分类
5.2 不同类型的列表
5.3 相对期望列表性能
5.3.1 用时间来交换内存空间和复杂性
5.3.2 避免就地突变
5.4 KOTLIN有哪些可用列表?
5.4.1 使用持久数据结构
5.4.2 实现不可变的、持久的单链表
5.5 列表操作中的数据共享
5.6 更多列表操作
5.6.1 标注的益处
5.6.2 连接列表
5.6.3 从列表末尾删除
5.6.4 使用递归对具有高阶函数(HOFs)的列表进行折叠
5.6.5 使用型变
5.6.6 创建foldRight的一个栈安全递归版本
5.6.7 映射和过滤列表
5.7 本章小结
第6章 处理可选数据
6.1 空指针问题
6.2 Kotlin如何处理空引用
6.3 空引用的替代方法
6.4 使用OPTION类型
6.4.1 从一个Option中获取值
6.4.2 将函数应用于可选值
6.4.3 处理Option组合
6.4.4 Option用例
6.4.5 其他组合选项的方法
6.4.6 用Option组合List
6.4.7 何时使用Option
6.5 本章小结
第7章 处理错误和异常
7.1 数据缺失的问题
7.2 Either类型
7.3 Result类型
7.4 Result模式
7.5 高级Result处理
7.6 映射Failture
7.7 添加工厂函数
7.8 应用作用
7.9 高级结果组合
7.10 本章小结
第8章 高级列表处理
8.1 长度问题
8.2 性能问题
8.3 记忆化的好处
8.3.1 处理记忆化的缺点
8.3.2 评估性能改进
8.4 List和Result组成
8.4.1 处理List返回Result
8.4.2 从List转换为Result
8.5 常见列表抽象
8.5.1 压缩和解压缩列表
8.5.2 通过索引访问元素
8.5.3 列表分裂
8.5.4 搜索子列表
8.5.5 处理列表的其它函数
8.6 列表的自动并行处理
8.6.1 并不是所有的计算都可以并行化
8.6.2 将列表分解为子列表
8.6.3 并行处理子列表
8.7 本章小结
第9章 与惰性配合
9.1 严格VS惰性
9.2 Kotlin和严格
9.3 Kotlin和惰性
9.4 懒惰的实现
9.4.1 组合惰性值
9.4.2 提升函数
9.4.3 映射和flatMapping惰性
9.4.4 用列表组成惰性
9.4.5 处理异常
9.5 深层次的惰性构成
9.5.1 惰性应用作用
9.5.2 不能没有惰性
9.5.3 创建一个惰性列表数据结构
9.6 处理流
9.6.1 折叠流
9.6.2 跟踪计算和函数应用
9.6.3 将流应用于具体问题
9.7 本章小结
第10章 使用树处理更多的数据
10.1 二叉树
10.2 了解平衡和不平衡的树
10.3 树的大小、高度和深度
10.4 空树和递归定义
10.5 多叶树
10.6 有序二叉树或二叉搜索树
10.7 插入顺序和树的结构
10.8 递归和非递归树遍历顺序
10.8.1 递归遍历树
10.8.2 非递归遍历树
10.9 实现二叉搜索树
10.9.1 理解型变和树
10.9.2 Tree类中的抽象函数
10.9.3 重载操作符
10.9.4 树中递归
10.9.5 从树中移除元素
10.9.6 合并任意树
10.10 关于折叠树
10.10.1 双函数折叠
10.10.2 单函数折叠
10.10.3 如何选择折叠实现
10.11 映射树
10.12 平衡树
10.12.1 旋转树
10.12.2 使用Day-Stout-Warren算法
10.12.3 自动平衡树
第11章 用高级树解决问题
11.1 自平衡树的性能更好,栈更安全
11.1.1 了解基本的红黑树结构
11.1.2 向红黑树中添加元素
11.1.3 从红黑树中移除元素
11.2 一个红黑树的用例:Map
11.2.1 实现Map
11.2.2 扩展Map
11.2.3 使用具有不可比较键的Map
11.3 实现功能优先队列
11.3.1 查看优先队列访问协议
11.3.2 探索优先级队列用例
11.3.3 查看实现需求
11.3.4 左倾堆数据结构
11.3.5 实现左倾堆
11.3.6 实现类似队列的接口
11.4 元素和有序列表
11.5 不可比较元素的优先队列
11.6 本章小结
第12章 函数式输入/输出
12.1 作用在上下文中是什么意思
12.1.1 处理作用
12.1.2 实现作用
12.2 读取数据
12.2.1 从控制台读取数据
12.2.2 从文件中读取数据
12.3 输入测试
12.4 全函数式输入/输出
12.4.1 使输入/输出全函数式
12.4.2 实现纯函数式的输入/输出
12.4.3 结合输入/输出
12.4.4 用IO处理输入
12.4.5 扩展IO类型
12.4.6 使IO类型堆栈安全
12.5 本章小结
第13章 与参与者共享可变状态
13.1 角色模型
13.1.1 理解异步消息传递
13.1.2 并行化处理
13.1.3 处理角色状态突变
13.2 角色框架实现
13.2.1 理解局限性
13.2.2 设计角色框架接口
13.3 AbstractActor的实现
13.4 让角色投入工作
13.4.1 实现乒乓球例子
13.4.2 并行运行计算
13.4.3 重排结果
13.4.4 优化性能
13.5 本章小结
第14章 解决常见功能性问题
14.1 断言和数据验证
14.2 函数和作用的重试
14.3 从文件中读入属性
14.3.1 加载属性文件
14.3.2 以字符串形式读取属性
14.3.3 生成更好的错误消息
14.3.4 将属性作为列表读取
14.3.5 读取枚举值
14.3.6 读取任意类型的属性
14.4 转换命令式风格的程序:XML阅读器
14.4.1 第1步:命令式风格的解决方案
14.4.2 第2步:将命令式风格的代码转换为函数式
14.4.3 第3步:将程序转换得更函数式
14.4.4 第4步:修复参数类型问题
14.4.5 第5步:使元素处理函数成为参数
14.4.6 第6步:对元素名称进行错误处理
14.4.7 第7步:对先前命令式代码的额外改进
14.5 本章小结
附录 A-将Kotlin与Java结合
A.1 创建和管理混合项目402
A.1.1 利用Gradle创建一个简单的项目
A.1.2 将Gradle项目导入IntelliJ
A.1.3 为项目增加依赖
A.1.4 创建多模块项目
A.1.5 为多模块项目增加依赖
A.2 Java库方法和Kotlin代码
A.2.1 使用Java基本类型
A.2.2 使用Java数值对象类型
A.2.3 对null值快速失败
A.2.4 使用Kotlin和Java的字符串类型
A.2.5 实现其他类型的转换
A.2.6 使用Java可变参数
A.2.7 在Java中指定可空性
A.2.8 调用getter方法和setter方法
A.2.9 使用保留字获取Java属性
A.2.10 调用已检查异常
A.3 SAM接口
A.4 Kotlin函数和Java代码
A.4.1 转换Kotlin属性
A.4.2 使用Kotlin公共字段
A.4.3 静态字段
A.4.4 将Kotlin函数作为Java方法调用
A.4.5 将Kotlin的类型转换为Java类型
A.4.6 函数类型
A.5 混合Kotlin/Java项目的特定问题
附录B-Kotlin中基于属性的测试
B.1 为何使用基于属性的测试
B.1.1 编写接口
B.1.2 编写测试程序
B.2 什么是基于属性的测试
B.3 抽象及基于属性的测试
B.4 基于属性的单元测试的依赖
B.5 编写基于属性的测试程序
B.5.1 创建自定义生成器
B.5.2 使用自定义生成器
B.5.3 通过更进一步抽象来简化代码