本篇内容
- 为什么要进行函数式编程
- 什么是函数式编程
- 声明式编程以及引用透明性
- 编写函数式Java的准则
- 迭代和递归
1.实现和维护系统
1.1 共享的可变数据
最终,我们刚才讨论的无法预知的变量修改问题,都源于共享的数据结构被你所维护的代码中的多个方法读取和更新。假设几个类同时都保存了指向某个列表的引用。那么到底谁对这个列表拥有所属权呢?如果一个类对它进行了修改,会发生什么情况?其他的类预期会发生这种变化吗?其他的类又如何得知列表发生了修改呢?我们需要通知使用该列表的所有类这一变化吗?抑或是不是每个类都应该为自己准备一份防御式的数据备份以备不时之需呢?换句话说,由于使用了可变的共享数据结构,我们很难追踪你程序的各个组成部分所发生的变化。
副作用:
函数的效果已经超出了函数自身的范畴。
- 除了构造器内的初始化操作,对类中数据结构的任何修改,包括字段的赋值操作(一个典型的例子是setter方法)
- 抛出一个异常。
- 进行输入/输出操作,比如向一个文件写数据。
从另一个角度来看“无副作用”的话,我们就应该考虑不可变对象。不可变对象是这样一种对象,它们一旦完成初始化就不会被任何方法修改状态。这意味着一旦一个不可变对象初始化完毕,它永远不会进入到一个无法预期的状态。你可以放心地共享它,无需保留任何副本,并且由于它们不会被修改,还是线程安全的。
“无副作用”这个想法的限制看起来很严苛,你甚至可能会质疑是否有真正的生产系统能够以这种方式构建。我们希望结束本章的学习之后,你能够确信这一点。一个好消息是,如果构成系统的各个组件都能遵守这一原则,该系统就能在完全无锁的情况下,使用多核的并发机制,因为任何一个方法都不会对其他的方法造成干扰。此外,这还是一个让你了解你的程序中哪些部分是相互独立的非常棒的机会。
1.2 声明式编程
命令式
一般通过编程实现一个系统,有两种思考方式。一种专注于如何实现,比如:“首先做这个,紧接着更新那个,然后……”
声明式编程
Optional<Transaction> mostExpensive =
transactions.stream()