Java8之旅(六) -- 使用lambda实现尾递归
前言
本篇介绍的不是什么新知识,而是对前面讲解的一些知识的综合运用。众所周知,递归是解决复杂问题的一个很有效的方式,也是函数式语言的核心,在一些函数式语言中,是没有迭代与while这种概念的,因为此类的循环通通可以用递归来实现,这类语言的编译器都对递归的尾递归形式进行了优化,而Java的编译器并没有这样的优化,本篇就要完成这样一个对于尾递归的优化。
什么是尾递归
本篇将使用递归中最简单的阶乘计算来作为例子
递归实现
/**
* 阶乘计算 -- 递归解决
*
* @param number 当前阶乘需要计算的数值
* @return number!
*/
public static int factorialRecursion(final int number) {
if (number == 1) return number;
else return number * factorialRecursion(number - 1);
}
这种方法计算阶乘比较大的数很容易就栈溢出了,原因是每次调用下一轮递归的时候在栈中都需要保存之前的变量,所以整个栈结构类似是这样的
5
4
3
2
1
------------------->
栈的深度
在没有递归到底之前,那些中间变量会一直保存着,因此每一次递归都需要开辟一个新的栈空间
尾递归实现
任何递归的尾递归版本都十分简单,分析上面栈溢出的原因就是在每次return的时候都会附带一个变量,因此只需要在return的时候不附带这个变量即可。说起来简单,该怎么做呢?其实也很容易,我们使用一个参数来保存上一轮递归的结果,这样就可以了,因此尾递归的阶乘实现应该是这样的代码。
/**
* 阶乘计算 -- 尾递归解决
*
* @param factorial 上一轮递归保存的值
* @param number 当前阶乘需要计算的数值
* @return number!
*/
public static int factorialTailRecursion(final int factorial, final int number) {
if (number == 1) return factorial;
else return factorialTailRecursion(factorial * number, number - 1);
}
使用一个factorial变量保存上一轮阶乘计算出的数值,这样return的时候就无需保存变量,整个的计算过程是
(5*4)20 -> (20*3) 60 -> (60*2) 120 -> return 120
这样子通过每轮递归结束后刷新当前的栈空间,复用了栈,就克服了递归的栈溢出问题,像这样的
return后面不附带任何变量的递归写法,也就是递归发生在函数最尾部,我们称之为'尾递归'。
使用lambda实现编译器的优化
很显然,如果事情这么简单的话,这篇文章也就结束了,和lambda也没啥关系
Java8之旅(六) -- 使用lambda实现尾递归的更多相关文章
- Java8函数之旅 (六) -- 使用lambda实现Java的尾递归
前言 本篇介绍的不是什么新知识,而是对前面讲解的一些知识的综合运用.众所周知,递归是解决复杂问题的一个很有效的方式,也是函数式语言的核心,在一些函数式语言中,是没有迭代与while这种概念的,因为此类 ...
- Java8之旅(七) - 函数式备忘录模式优化递归
前言 在上一篇开始Java8之旅(六) -- 使用lambda实现Java的尾递归中,我们利用了函数的懒加载机制实现了栈帧的复用,成功的实现了Java版本的尾递归,然而尾递归的使用有一个重要的条件就是 ...
- 开始Java8之旅(四) --四大函数接口
前言 Java8中函数接口有很多,大概有几十个吧,具体究竟是多少我也数不清,所以一开始看的时候感觉一脸懵逼,不过其实根本没那么复杂,毕竟不应该也没必要把一个东西设计的很复杂. 几个单词 在学习 ...
- Java8学习之旅2---基于Lambda的JDBC编程
Java8的Lambda表达式确实是一个很好的特性.可是在哪些场合下使用.事实上还是须要细致考虑的.我们当然不能为了使用而使用,而是须要找到切实实用的场合.在JDBC编程中,比如查询语句,首先须要进行 ...
- java8新特性1:lambda表达式和函数式接口
1.lambda的介绍: 1.1.为什么java语言需要引入lambda表达式? java语言诞生于1995年,历史时间已经相对较长了.在其后的各种新型编程语言中,都有着lambda表达式的内容,并且 ...
- Java8之——简洁优雅的Lambda表达式
Java8发布之后,Lambda表达式,Stream等等之类的字眼边慢慢出现在我们字眼.就像是Java7出现了之后,大家看到了“钻石语法”,看到了try-with-resource等等.面对这些新东西 ...
- java8 新特性入门 stream/lambda
Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利.高效的聚合操作(aggregate operation),或者大批量数据操作 (b ...
- Java8新特性之一:Lambda表达式
Java8是自java5之后最重大的一次更新,它给JAVA语言带来了很多新的特性(包括编译器.类库.工具类.JVM等),其中最重要的升级是它给我们带来了Lambda表达式和Stream API. 1. ...
- java8 学习之路之lambda
前言 目前我们知道java的版本已经发布到12了,之前的项目用的是JDK1.7,听说JDK1.8的改动相对来说大一些,因此抽空学学JDK1.8的一些新特性.本人也是通过阅读Java8实战这本书做一些小 ...
随机推荐
- How To:禁用ubuntu全局菜单(global menu)的方法
刚从windows转过来的新手可用会觉得ubuntu unity下的全局菜单(global menu)用起来很不方便.下边是介绍去除全局菜单的方法 1.打开终端(可以去dash主页里面搜,也可以直接按 ...
- C#程序及批处理中确定windows操作系统的方法
先上一段代码: private void Form1_Load(object sender, EventArgs e) { OperatingSystem os = Environment.OSVer ...
- 通过SDK和API获取阿里云RDS的监控数据
阿里云的RDS自带的监控系统获取数据不怎么直观,想要通过API获取数据通过zabbix显示,因为网上资料缺乏和其他一些原因,获取API签名很困难,但使用阿里云的SDK可以完美避开获取签名的步骤. 阿里 ...
- session get和load方法对比
get测试代码如下: public class Test { public static void main(String[] args) { // TODO Auto-generated metho ...
- java如何将html过滤为纯文本
java开发中jsp页面可以嵌套很多插件就可以将html形式的文本直接转化为纯文本,但是如果你已经保存下来或者没有运用插件,这个额html形式的文本你该怎么转化为纯文本呢?有次我将公告保存了html形 ...
- RabbitMQ消息队列之一:RabbitMQ的环境安装及配置
RabbitMQ简介: MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们 ...
- ArrayList 和 LinkedList 的实现与区别
(转载请标明出处) 1.ArrayLis t的实现 2.LinkedLis t的实现 3.ArrayList 和 LinkedList 的区别 ArrayList 的实现: 1.MyArrayList ...
- 变量的声明和定义以及extern的用法
变量的声明和定义以及extern的用法 变量的声明不同于变量的定义,这一点往往容易让人混淆. l 变量 ...
- Nexus 私有仓库搭建与 Maven 集成
Nexus 私有仓库搭建与 Maven 集成 |作者:RexFang |出处:http://www.cnblogs.com/rexfang/ |关于作者:Java 程序员一枚 |版权:本文版权归作者和 ...
- 1001 数组中和等于K的数对 1002 数塔取数问题 1003 阶乘后面0的数量 1004 n^n的末位数字 1009 数字1的数量
1001 数组中和等于K的数对 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 给出一个整数K和一个无序数组A,A的元素为N个互不相同的整数,找出数组A中所有和等于K ...