Java递归更好的方法?
通常情况下,我会按照以下步骤进行代码验证:Java递归更好的方法?,java,Java,通常情况下,我会按照以下步骤进行代码验证: public static void Menu() { Scanner keyboard = new Scanner(System.in); if (!keyboard.hasNextInt()) { System.out.println("Incorrect input, try again"); Menu(); } else { // switch
public static void Menu()
{
Scanner keyboard = new Scanner(System.in);
if (!keyboard.hasNextInt())
{
System.out.println("Incorrect input, try again");
Menu();
}
else
{
// switch statement etc
}
}
我只是想知道这是个坏习惯吗?如果是这样,除了使用递归,还有什么更好的方法。我使用递归来获得数字的幂和其他一些东西,因此我理解了它的想法。这是递归,在这种情况下,这是一种不好的做法,因为如果输入错误数据太多次,将导致堆栈溢出异常。尝试
而不是循环:
Scanner scanner = new Scanner(System.in);
int choice = 0;
while (scanner.hasNext()) {
if(scanner.hasNextInt()) {
choice = scanner.nextInt();
break;
}
System.out.println("Incorrect input, try again");
scanner.next();
}
scanner.close();
// switch statement etc
switch(choice) {
//...
}
这将只创建一个扫描仪
实例,并将保持平稳运行,直到输入一些有效值
当满足以下条件时,保持递归:
- 如果它增加了代码可读性/可维护性
- 如果没有堆栈溢出的风险(您知道递归代码的执行次数不会超过有限的次数)
循环的性能通常也会更好,但如果使用递归,大多数情况下,在您注意到显著的性能损失之前,您就会遇到堆栈溢出。循环总是比递归好。在递归中,建立内部堆栈。
递归还需要一个比循环慢的方法子程序跳转。在这种情况下,我会说是的
您可以在此方法中声明一个新对象。想想记忆李>
在这种情况下,while循环会做得更好
edit://to slow当递归调用的数量不固定时,这种类型的递归是不好的。在一些错误的尝试之后,您可能会出现OutOfMemoryError
异常。所以最好找一个替代方法,或者如果你不得不这样使用递归,放置一个计数器
,它允许您进行一定次数的尝试。使用递归算法的要点与其说是一种方法本身调用,不如说是一种方法本身返回一些结果以供进一步处理:有一个调用堆栈正在构建,但有一定的深度(希望如此)递归终止,结果被传递回堆栈以生成一些最终结果
您的示例只是通过从自身重复调用Menu()
来构建调用堆栈,但没有返回结果,因此我认为这根本不是正确的递归,但它只会用无用的杂乱填充堆栈。System.out.println()Edit://再次减慢。。这里发生了什么,但是在输入一个int之前,是否会反复输出“输入错误,再试一次”?它会说一次然后等待输入吗?当我尝试此方法并键入一封信时,它不断重复错误数千次。找不到文章,但我也阅读了JIT编译器无法优化递归(尾部递归除外),因此最好尽可能避免它,除非您考虑JIT。@JaredBeekman如果您能找到引用,它在这里特别有用,因为在OP的代码中,对Menu()
的递归调用处于尾部位置。如果编译器可以优化它,那么这本质上就是一个循环,通过将扫描器作为函数的参数,可以消除额外的扫描器分配。在挖掘了大约一个小时后,我找不到我读过的原始文章,但我确实找到了一堆说明这一点的文章/帖子(这可能已经改变,因为其中一些是“旧的”)由于JVM需要完全访问调用堆栈,因此即使尾部调用递归也可能无法优化。这是一个很好的讨论和参考。尽管添加了Lambda表达式,但Java 8在处理递归的方式上似乎有所不同。也就是说,OP应该能够发送扫描程序,在调用之前实例化函数调用,作为一个参数,只需使用它是一个引用的事实来防止多个实例化,然后只需记住在以后关闭它(或者根据Java的版本使用try with resources方案)。