读Java实战(第二版)笔记09_函数式的思考

Posted lying7

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了读Java实战(第二版)笔记09_函数式的思考相关的知识,希望对你有一定的参考价值。

1. 规则

1.1. 传递参数,返回结果

1.1.1. 异常和中断都不算返回结果

1.2. 减少共享的可变数据结构能帮助你降低维护和调试程序的代价

2. 耦合性

2.1. 软件系统中各组件之间是否相互独立

3. 内聚性

3.1. 系统的各相关部分之间如何协作

4. 无状态的行为

4.1. 流水线中的函数不会由于需要等待从另一个方法中读取变量,或者由于需要写入的变量同时有另一个方法正在写而发生中断

4.2. 无须担心锁引起的各种问题

4.3. 充分发掘系统的并发能力

5. 副作用

5.1. 函数的效果已经超出了函数自身的范畴

5.2. 除了构造器内的初始化操作,对类中数据结构的任何修改,包括字段的赋值操作

5.3. 抛出一个异常

5.4. 进行输入/输出操作

6. 无副作用

6.1. 纯粹的

6.2. 如果一个方法既不修改它内嵌类的状态,也不修改其他对象的状态,使用return返回所有的计算结果

6.3. 如果构成系统的各个组件都能遵守这一原则,该系统就能在完全无锁的情况下,使用多核的并发机制,因为任何一个方法都不会对其他的方法造成干扰

6.4. 了解程序中哪些部分是相互独立的

7. 不可变对象

7.1. 一旦完成初始化就不会被任何方法修改状态

7.2. 一旦一个不可变对象初始化完毕,它永远不会进入到一个无法预期的状态

7.3. 线程安全的

8. 声明式编程

8.1. 关注要做什么

8.2. 更加接近问题陈述

9. 命令式编程

9.1. 指令和计算机底层的词汇非常相近

9.2. 专注于如何实现

10. 引用透明性

10.1. 没有可感知的副作用

10.1.1. 不改变对调用者可见的变量

10.1.2. 不抛出异常

10.1.3. 不进行I/O

10.2. 如果一个函数只要传递同样的参数值,总是返回同样的结果,那这个函数就是引用透明的

11. 记忆化

11.1. 缓存

11.2. 对代价昂贵或者需长时间计算才能得到结果的变量值的优化

11.2.1. 通过保存机制而不是重复计算

12. 函数式编程

12.1. 程序有一定的副作用

12.1.1. 该副作用不会被其他的调用者感知

12.1.1.1. 如果没人能感知的话,函数式也允许进行变更,这意味着可以修改局部变量

12.1.2. 调用者不需要知道,或者完全不在意这些副作用

12.2. 如果有副作用

12.2.1. 必须设法隐藏它们的非函数式行为

12.2.2. 否则就不能调用这些方法

12.2.3. 需要确保它们对数据结构的任何修改对于调用者都是不可见的,可以通过首次复制,或者捕获任何可能抛出的异常实现这一目的

12.3. 函数式的函数或方法都只能修改本地变量

12.3.1. 所有的字段都为final类型

12.3.2. 所有的引用类型字段都指向不可变对象

12.3.3. 引用的对象都应该是不可修改的对象

12.4. 选择使用引用透明的函数

12.5. 不应该抛出任何异常

12.5.1. 选择在本地局部地使用异常,避免通过接口将结果暴露给其他方法,这种方式既取得了函数式的优点,又不会过度膨胀代码

13. 局部函数式(partial function)

13.1. 大多数的输入值都返回一个确定的结果

13.2. 对另一些输入值,它的结果是未定义的,甚至不返回任何结果

13.2.1. 除法,如果除法的第二操作数是0

13.2.2. 开平方运算,开平方的参数为负数

13.2.3. 使用Optional类型

14. 纯粹的函数式编程

14.1. 不提供像while或者for这样的迭代结构

14.1.1. 这种结构经常隐藏着陷阱,诱使你修改对象

15. 递归recursion

15.1. 函数式编程特别推崇的一种技术

15.2. 培养你思考要“做什么”的编程风格

15.3. 每个程序都能使用无须修改的递归重写,通过这种方式避免使用迭代

15.3.1. 采用递归可以取代迭代式的结构,比如while循环

15.3.2. 使用递归,可以消除每步都需更新的迭代变量

15.4. 递归的形式通常效率都更差一些

15.4.1. 因为每次执行递归方法调用都会在调用栈上创建一个新的栈帧,用于保存每个方法调用的状态(即它需要进行的乘法运算),这个操作会一直指导程序运行直到结束

15.4.2. 很容易遭遇StackOverflowError异常

15.5. 大多数时候编程的效率要比细微的执行时间差异重要得多

15.6. 尾调优化(tail-call optimization)

15.6.1. 编写方法的一个迭代定义,不过迭代调用发生在函数的最后

15.6.1.1. 调用发生在尾部

15.6.2. Java不支持这种优化

15.6.3. Scala、Groovy和Kotlin,支持对这种形式的递归的优化

15.6.3.1. 最终实现的效果和迭代不相上下(它们的运行速度几乎是相同的)

以上是关于读Java实战(第二版)笔记09_函数式的思考的主要内容,如果未能解决你的问题,请参考以下文章

读Java实战(第二版)笔记19_尾声

读Java实战(第二版)笔记04_用流收集数据

读Java实战(第二版)笔记13_Java模块系统

读Java实战(第二版)笔记08_默认方法

读Java实战(第二版)笔记12_重构测试和调试

读Java实战(第二版)笔记03_引入和使用流