Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java递归更好的方法?_Java - Fatal编程技术网

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方案)。