《Java in Action》-1 第13章 函数式的思考

来源:互联网 发布:韩国淘宝模特红人 编辑:程序博客网 时间:2024/06/08 10:47

第13章 函数式的思考


13.1 实现和维护系统


13.1.1 共享的可变数据

不可变对象一旦完成初始化就不会被任何方法修改状态。可以共享,线程安全的。


13.1.2 声明式编程

通过编程实现一个系统,有两种思考方式。

一种专注于如何实现,称为“命令式”编程。

另一种则更加关注要做什么,称为“声明式”编程。制定规则,给出了希望实现的目标,让系统来决定如何实现这个目标,它带来的好处非常明显,用这种方式编写的代码更加接近问题陈述了。


13.1.3 为什么要采用函数式编程

函数式编程具体实践了前面介绍的声明式编程和无副作用计算。


13.2 什么是函数式编程

它是一种使用函数进行编程的方式。

当谈论函数式时,我们想说的其实是“像数学函数那样——没有副作用”。


13.2.1 函数式Java编程

要被称为函数式,函数或者方法不应该抛出任何异常。

如果不使用异常,请使用Optional<T>类型。


13.2.2 引用透明性

“没有可感知的副作用”的这些限制都隐含着引用透明性。如果一个函数只要传递同样的参数值,总是返回同样的结果,那这个函数就是引用透明的。

在函数式编程中,你应该选择使用引用透明的函数。


13.2.3 面向对象的编程和函数式编程的对比


13.3 递归和迭代

迭代式的阶乘计算:

static int factorialIterative(int n) {

int r = 1;

for(int i = 1; i <=n; i++) {

r *= i;

}

return r;

}


递归式的阶乘计算

static long factorialRecursive(long n) {

reurn n == 1 ? 1 : n * factorialRecursive(n-1);

}


基于Stream的阶乘

static long factorialStreams(long n) {

return LongStream.rangeClosed(1,n)

.reduce(1,(long 1,long b) -> a * b);

}


基于“尾-递”的阶乘

static long factorialTailRecursive(long n) {

return factorialHelper(1,n);

}

static long factorialHelper(long acc,long n) {

return n == 1 ? acc : factorialHelper(acc * n, n-1);

}

"尾-递"类型的函数递归调用发生在方法的最后,不需要在不同的栈帧上保存每次递归计算的中间值,编译器能够自行决定复用某个栈帧进行计算。


13.4 小结


*从长远看,减少共享的可变数据结构能帮助你降低维护和调试程序的代价。

*函数式编程支持无副作用的方法和声明式编程。

*函数式方法可以由它的输入参数及输出结果进行判断

*如果一个函数使用相同的参数值调用,总是返回相同的结果,那么它是引用透明的。采用递归可以取得迭代式的结构,比如while循环。

*相对于Java语言中传统的递归,“尾-递”可能是一种更好的方式,它开启了一扇门,让我们有机会最终使用编译器进行优化。



0 0
原创粉丝点击