【笔记】慎用Java递归调用
来源:互联网 发布:tplink网络设置 编辑:程序博客网 时间:2024/05/01 04:49
在java语言中,使用递归调用时,如果过多的调用容易造成java.lang.StackOverflowError即栈溢出和程序执行过慢。这是一个潜在Bug和影响程序执行效率问题,需要谨慎使用。
下面先看造成java.lang.StackOverflowError即栈溢出问题:
public class RecursionTest{public static void recursion(int totalTimes,int time){if(totalTimes > 1){System.out.println("这是第 " + time + "次调用!");totalTimes--;time++;recursion(totalTimes, time);}else{System.out.println("调用结束,共调用了" + time + "次");return;}}public static void main(String[] args){int totalTimes = 1000000;int time = 1;long startTime = System.currentTimeMillis();System.out.println("嵌套调用起始时间:" + startTime);recursion(totalTimes, time);System.out.println("嵌套调用结束时间:" + System.currentTimeMillis());System.out.println("总耗时:" + (System.currentTimeMillis() - startTime));System.out.println("------------------------------------------------------------");}}修改“totalTimes”,当到达一定值时,报如下错误:
在开发时,要注意避免该问题,特别是递归过多调用时,最好改为for或者whlie来代替。
如下cycle()方法:
public static void cycle(int totalTimes, int time){if(totalTimes > 1){System.out.println("这是第 " + time + "次调用!");}else{System.out.println("调用结束,共调用了" + time + "次");}}代替recuresion()方法:
public static void recursion(int totalTimes,int time){if(totalTimes > 1){System.out.println("这是第 " + time + "次调用!");totalTimes--;time++;recursion(totalTimes, time);}else{System.out.println("调用结束,共调用了" + time + "次");return;}}
再看一下对程序执行效率的影响:
仍然使用上面的例子,分别cycle()方法和在main()方法中加入如下代码:
startTime = System.currentTimeMillis();System.out.println("循环调用起始时间:" + startTime);for (int index = totalTimes; index > 0; index--){cycle(index, time);time++;}System.out.println("循环调用结束时间:" + System.currentTimeMillis());System.out.println("总耗时:" + (System.currentTimeMillis() - startTime));System.out.println("--------------------整个代码如下:
public class RecursionTest{public static void recursion(int totalTimes,int time){if(totalTimes > 1){System.out.println("这是第 " + time + "次调用!");totalTimes--;time++;recursion(totalTimes, time);}else{System.out.println("调用结束,共调用了" + time + "次");return;}}public static void cycle(int totalTimes, int time){if(totalTimes > 1){System.out.println("这是第 " + time + "次调用!");}else{System.out.println("调用结束,共调用了" + time + "次");}}public static void main(String[] args){int totalTimes = 100000;int time = 1;long startTime = System.currentTimeMillis();System.out.println("嵌套调用起始时间:" + startTime);recursion(totalTimes, time);System.out.println("嵌套调用结束时间:" + System.currentTimeMillis());System.out.println("总耗时:" + (System.currentTimeMillis() - startTime));System.out.println("------------------------------------------------------------");startTime = System.currentTimeMillis();System.out.println("循环调用起始时间:" + startTime);for (int index = totalTimes; index > 0; index--){cycle(index, time);time++;}System.out.println("循环调用结束时间:" + System.currentTimeMillis());System.out.println("总耗时:" + (System.currentTimeMillis() - startTime));System.out.println("------------------------------------------------------------");}}
分别测试totalTimes为500,1000,3000对比结果:
500次:
1000次:
3000次:
以下是从网络上摘抄的:
根本原因是这样的,对于每一个线程,都有一个java栈 ,当有一个方法被调用的时候,会产生一些跟这个方法相关的信息,如方法名,参数,中间变量等等,这些叫做栈帧 ,当一个方法执行完毕 这个栈帧才会从栈顶pop掉 你递归的话 会一直向栈里push栈帧 而这个java栈是有一定的长度或深度的,当栈满了,无法再进行push的时候 就出现你上面的异常了,解决办法的话 就不要用递归操作 改用for 而且平时也不建议用递归的,效率太低了 .
栈溢出了,JVM依然是采用栈式的虚拟机,这个和C和Pascal都是一样的。函数的调用过程都体现在堆栈和退栈上了。你调用构造函数的“层”太多了,以致于把栈区溢出了。
通常来讲,一般栈区远远小于堆区的,因为函数调用过程往往不会多于上千层,而即便每个函数调用需要1K的空间(这个大约相当于在一个C函数内声明了256个int类型的变量),那么栈区也不过是需要1MB的空间。通常栈的大小是1-2MB的。通常递归也不要递归的层次过多,很容易溢出.
栈溢出了,JVM依然是采用栈式的虚拟机,这个和C和Pascal都是一样的。函数的调用过程都体现在堆栈和退栈上了。你调用构造函数的“层”太多了,以致于把栈区溢出了。
通常来讲,一般栈区远远小于堆区的,因为函数调用过程往往不会多于上千层,而即便每个函数调用需要1K的空间(这个大约相当于在一个C函数内声明了256个int类型的变量),那么栈区也不过是需要1MB的空间。通常栈的大小是1-2MB的。通常递归也不要递归的层次过多,很容易溢出.
对java.lang.StackOverflowError的分析:
原因:运行一个程序,JVM会开辟一块内存空间去储存程序进行时的某些信息,当程序运行时需要储存的信息超过了分配的空间,就会出现那样的问题.比如死循环,
解决:首先从程序代码优化方面着手,检查是否有死循环、递归等程序,如果有,修正、优化相关代码。
- 【笔记】慎用Java递归调用
- 慎用Java递归调用
- java中为什么我们要慎用递归
- Java学习笔记-方法递归调用
- 如果要用Java实现算法,一定慎用递归
- Java 学习笔记 (10) - Java 函数的递归调用
- 递归调用学习笔记
- 马士兵java视频学习笔记第二章:递归调用
- java中的递归调用
- java的递归调用
- Java递归调用
- java方法递归调用
- Java方法递归调用
- java之递归调用
- java中的递归调用
- 笔记-<函数的递归调用>
- java学习笔记--char型字符串要慎用
- JAVA递归学习笔记
- JS简单应用——身份证号码信息截取
- 关于过滤文件、过滤文件夹、过滤路径的几个想法
- log4j配置详解
- Uva 11054 洒交易(扫描法)
- Linux 修改 网卡名称 小记
- 【笔记】慎用Java递归调用
- 如何配置NetBeans启动后语言为英文
- JS读取文本文件
- 用到的oracle sql语句-001
- VC设置鼠标形状
- 请教sql执行效率问题(inner join 和 where)
- 程序员喝酒
- struts2国际化语言切换
- JAVA调用exe可执行文件