捕获异常时的不定式递归

Fan*_*Fan 2 java recursion exception java.util.scanner

这是我输入学号的代码:当用户以意想不到的格式输入数字时,我会要求他们通过递归重新输入.但它最终会产生一个不定式的递归.为什么?

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

ysh*_*vit 7

仔细看看javadocsScanner.nextInt:

InputMismatchException如果下一个标记无法转换为有效的int值,则抛出此方法,如下所述.如果翻译成功,扫描仪将超过匹配的输入.(重点补充)

如果不成功,则扫描仪不会前进.这意味着如果你nextInt()再次尝试调用,你将尝试从以前相同的令牌中获取一个int ,并且你将再次得到一个InputMismatchException.

你的代码基本上说:尝试将下一个标记读作int.如果失败,请尝试再次尝试将令牌读作int.如果失败,请尝试再次尝试将令牌读作int.如果失败了......(依此类推,直到你得到StackOverflowException过多的递归).

如果你想为此使用递归,你可能应该使用 next()跳转到下一个标记.并且只捕获InputMismatchException,这样你就不会捕获NoSuchElementException(这不会发生System.in,但一般来说是好的做法 - 如果你以后决定从文件中读取,并且该文件已经到了终点怎么办?).

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

更好的方法是避免使用异常来控制逻辑.要做到这一点,你必须提前知道是否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();
  }
}
Run Code Online (Sandbox Code Playgroud)

这里的优势 - 除了一般的"不使用控制流程的例外"建议 - 基本情况是非常清楚的.如果有一个int准备就绪,这是你的基本情况; 如果没有,你必须推进扫描仪,然后再试一次.

  • @KickButtowski基本情况基本上是`nextInt`成功返回的时候.这只是第一次发生(如果用户输入有效字符串),或者它永远不会发生(因为扫描程序永远不会丢弃当前令牌并尝试使用下一个令牌). (3认同)
  • @KickButtowski我不完全确定Luiggi的立场是什么,所以我不能说.我认为捕获和处理`InputMismatchException`(无论是通过递归,还是继续`while`循环,或其他什么)都没问题.我认为Luiggi的建议(我同意的)不是在这样的情况下捕获普通的`Exception`(在你应该捕获`Exception`的情况下相当少),而是要抓住_specific_错误的情况你想要处理. (2认同)
  • 哦,对不起,我只是重新阅读`Scanner`的文档(我几乎从不使用它),并看到它有一个方法`hasNextInt`.所以你应该使用它.如果返回true,则返回`nextInt`.否则,使用令牌并递归(或以任何方式循环).我会更新我的答案. (2认同)