跳到内容
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.最终实现的效果和迭代不相上下(它们的运行速度几乎是相同的)