Java 捕获异常时的不定式递归

Java 捕获异常时的不定式递归,java,exception,recursion,java.util.scanner,Java,Exception,Recursion,Java.util.scanner,以下是我输入学号的代码: 当用户以意外的格式输入数字时,我将要求他们通过递归重新输入。但它以一个不定式递归结束。为什么? private static int inputStudentNumber(){ System.out.println("Enter the student number:"); int studentNum; try { //Scanner in initialized before calling this method

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

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();
    }
}

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

catch(Exception e) {
    ....
}
这里的最佳实践是只捕获您期望的特定异常,因此应该是:

catch(InputMismatchException e) {
    ....
}
如果执行此操作,则.nextInt()中抛出的任何
都将正确传播到顶部,您可能会看到in未初始化或出现类似问题

有关
nextInt()
可以引发的异常,请参见此处。

仔细看看:

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

如果不成功,则说明扫描仪不先进。这意味着,如果您再次尝试调用
nextInt()
,您将尝试从与以前相同的令牌获取int,并且您将再次获得
inputmaschException

您的代码基本上是这样的:尝试将下一个令牌作为int读取。如果失败,则递归以再次尝试将令牌作为int读取。如果失败,则递归尝试再次将令牌读取为int。如果失败了。。。(依此类推,直到您从过多的递归中得到一个
StackOverflowException

如果要对此使用递归,可能应该使用
next()
跳到下一个标记。并且只捕获
输入不匹配异常
,这样您就不会同时捕获
NoTouchElementException
(这在
系统中不会发生,但通常是一种好的做法——如果您以后决定从文件中读取,并且该文件已到达其结尾怎么办?)

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

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就绪,那就是你的基本情况;如果没有,您必须先打开扫描仪,然后再试一次

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


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

我想您理解错了recursion@JorgeCampos好的,它实际上是递归,只是使用一个
异常的出现作为它的返回条件。这会让我的眼睛抽搐,但是…中的
是初始化的扫描仪吗?在
catch
块中添加一些日志记录(例如,
System.out.println()
语句)。找出抛出的异常类型。@ryanyyuyu Yes“in”是系统中的扫描仪in@KickButtowski基本情况是
nextInt
成功返回。这只是第一次发生(如果用户输入有效字符串),或者永远不会发生(因为扫描程序永远不会放弃当前令牌并尝试下一个令牌)。@KickButtowski没有基本情况。事实上,应该不惜一切代价避免这种代码。这是使用
catch(异常e)
不好的一个很好的例子。同样,OP不应从此异常中恢复,相反,他/她必须更改设计以避免此情况。在我之前的评论中显示了一个变化。@KickButtowski我不完全确定Luiggi的立场是什么,所以我不能说。我认为捕获并处理
输入不匹配异常
(无论是通过递归,还是继续
while
循环,或者其他方式)是很好的。我认为Luiggi的建议(我同意)是,在这种情况下,不要只捕获普通的
异常
(应该捕获
异常
)的情况相当少,而是捕获您想要处理的特定错误情况。@KickButtowski思考一下:您是否编写过代码来捕获
NullPointerException
或任何其他特定但意外的
运行时异常
?因为这是同样的情况。最好的选择是:更改代码以避免这些意外的
运行时异常
。如果您知道必须处理特定的异常(即使对于
RuntimeException
的子类也是如此),那么请捕获并正确处理它们。我并不反对在这种情况下不捕获
输入不匹配异常
,但如果可以避免,它会更好。哦,对不起,我只是重新阅读了
扫描仪的文档(我几乎从未使用过它),并看到它有一个方法
hasnetint
。所以你应该用它来代替。如果返回true,则返回
nextInt
。否则,使用令牌并递归(或循环,任意一种方式)。我会更新我的答案。
} catch(InputMismatchException e) {
    System.out.println("Invalid input, it can only be integer.");
    in.next(); // skip this token
    return inputStudentNumber();
}
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();
  }
}