【问题标题】:Infinitive recursion when catching an Exception捕获异常时的不定式递归
【发布时间】:2015-01-27 22:36:54
【问题描述】:

这是我输入学号的代码: 当用户以意外的格式输入数字时,我会要求他们通过递归重新输入。但它以不定式递归结束。为什么?

private static int inputStudentNumber(){
    System.out.println("Enter the student number:");
    int studentNum;
    try {
        //Scanner in initialized before calling this method
        studentNum = in.nextInt();
        return studentNum;
    } catch(Exception e) {
        System.out.println("Invalid input, it can only be integer.");
        return inputStudentNumber();
    }
}

【问题讨论】:

  • 我认为你误解了递归
  • @JorgeCampos 嗯,它真的递归,只是使用Exception的出现作为它的返回条件。它让我的眼睛抽搐,但是......
  • in初始化扫描器吗?
  • catch 块中添加一些日志记录(例如,System.out.println() 语句)。找出正在抛出什么样的Exception
  • @ryanyuyu 是的“in”是来自 System in 的扫描仪

标签: java exception recursion java.util.scanner


【解决方案1】:

仔细看看javadocs for Scanner.nextInt

如果下一个标记无法转换为如下所述的有效 int 值,则此方法将抛出 InputMismatchException如果翻译成功,扫描仪会跳过匹配的输入。 (强调)

如果不成功,则说明扫描仪不高级。这意味着,如果您尝试再次调用 nextInt(),您将尝试从 相同的令牌 中获取一个 int,并且您将再次获得一个 InputMismatchException

您的代码基本上说:尝试将下一个标记读取为 int。如果失败,则递归尝试再次将令牌读取为 int。如果失败,则递归尝试再次将令牌读取为 int。如果失败...(依此类推,直到您从太多递归中得到StackOverflowException)。

如果你想为此使用递归,你应该使用next() 跳到下一个标记。并且只捕获InputMismatchException,这样您就不会捕获NoSuchElementExceptionSystem.in 不会发生这种情况,但通常是一种很好的做法——如果您稍后决定从文件中读取,那该怎么办?文件已结束?)。

} catch(InputMismatchException e) {
    System.out.println("Invalid input, it can only be integer.");
    in.next(); // skip this token
    return inputStudentNumber();
}

更好的方法是首先避免使用异常来控制您的逻辑。为此,您必须提前知道nextInt 是否会成功。幸运的是,hasNextInt() 可以让你做到这一点!

private static int inputStudentNumber() {
  System.out.println("Enter the student number:");
  if (in.hasNextInt()) {
    return in.nextInt();
  } else {
    System.out.println("Invalid input, it can only be integer.");
    in.next(); // consume the token
    return inputStudentNumber();
  }
}

这里的优势——除了一般的“不要对控制流使用异常”建议——基本情况非​​常清楚。如果有一个 int 准备好了,那就是你的基本情况;如果没有,您必须推进扫描仪并重试。

【讨论】:

  • @KickButtowski 基本情况基本上是nextInt 成功返回。只是要么第一次发生(如果用户输入了一个有效的字符串),要么永远不会发生(因为扫描器永远不会丢弃当前的令牌并尝试下一个)。
  • @KickButtowski 这没有基本情况。事实上,应该不惜一切代价避免这种代码。这是一个很好的例子,为什么使用catch (Exception e) 不好。同样,OP 不应该从此异常中恢复,而是他/她必须更改设计以避免这种情况。我之前的评论中显示了更改。
  • @KickButtowski 我不完全确定 Luiggi 的立场是什么,所以我不能说。我认为捕获和处理InputMismatchException 很好(无论是通过递归还是继续while 循环,或其他方式)。我认为 Luiggi 的建议(我同意)不是在这样的情况下只捕捉普通的Exception(在相当少的情况下你应该捕捉Exception),而是捕捉 特定的 要处理的错误情况。
  • @KickButtowski 想一想:你有没有写过代码来捕捉NullPointerException 或任何其他具体但出乎意料的RuntimeException?因为这是同样的情况。最好的选择:更改代码以避免这些意外的RuntimeException。如果你知道你必须处理一个特定的异常(即使是RuntimeException 的子类),然后正确地捕获和处理它们。在这种情况下,我不反对不抓InputMismatchException,但如果可以避免这种情况,那就更好了。
  • 哦,抱歉,我刚刚重新阅读了Scanner 的文档(我几乎从不使用它),发现它有一个方法hasNextInt。所以你应该改用它。如果返回 true,则返回 nextInt。否则,使用令牌并递归(或循环,无论哪种方式)。我会更新我的答案。
【解决方案2】:

问题在于,如果输入一个非整数作为输入,那么扫描仪不会使用该输入。所以你就继续读下去吧。

您可能只想将输入读取为字符串,然后尝试单独转换它。

【讨论】:

    【解决方案3】:

    您的问题可能是 in.nextInt() 正在抛出异常。我看到的代码味道是您使用的:

    catch(Exception e) {
        ....
    }
    

    这里的最佳做法是只捕获您期望的特定异常,因此应该是:

    catch(InputMismatchException e) {
        ....
    }
    

    如果你这样做,那么 in.nextInt() 抛出的任何东西都会正确地传播到顶部,你可能会看到 in 没有初始化或出现类似问题。

    请参阅此处了解nextInt() 可以抛出的异常。 http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html#nextInt()

    【讨论】:

      【解决方案4】:
      try this...
      
      private static int inputStudentNumber(){
          System.out.println("Enter the student number:");
          int studentNum;
          int var = 1;
      while(var ==1)´
      {
          try{
              studentNum = in.nextInt();
              var=0;
              return studentNum;
          }catch(Exception e){
              System.out.println("Invalid input, it can only be integer.");
              var=1;
              return inputStudentNumber();
          }
      }
      
      
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-17
        • 1970-01-01
        • 1970-01-01
        • 2018-08-29
        • 2010-12-07
        • 1970-01-01
        相关资源
        最近更新 更多