由于递归而导致的无限循环(介绍性)

时间:2014-01-09 00:54:40

标签: java recursion infinite-loop

我正在尝试编写一种方法,使人们可以通过扫描程序输入整数,而不会因程序异常而导致程序崩溃。这是我最初的所作所为:(此处,sc是扫描仪对象)

    public static int inputInt(String message) {                                            
    int returnval = 0;
    System.out.println(message);
    try {
        returnval = sc.nextInt();
    } catch (Exception ex) {
        System.out.println("You must enter an integer.");
        inputInt(message);
    }
    return returnval;
}

当我使用无效输入测试程序时,启动了无限循环,消息和"您必须输入一个整数"在被Eclipse停止之前被多次打印。 我使用以下代码修复了这个问题:

 public static int inputInt(String message) { 
    int returnval = 0;
    System.out.println(message);
    String valstring = sc.nextLine();
    try {
        returnval = Integer.parseInt(valstring);
    } catch (Exception ex) {
        System.out.println("You must enter an integer.");
        inputInt(message);
    }
    return returnval;
}

为什么第一种方法失败,而第二种方法失败?可能有更清洁的方法来实现这个目标吗?

2 个答案:

答案 0 :(得分:2)

是的,方法更简洁:使用hasNextInt

public static int inputInt(String message) {
    System.out.println(message);
    while (!sc.hasNextInt()) {
        sc.nextLine(); // clear the bad input first

        System.out.println("You must enter an integer.");
        System.out.println(message); // why use recursion? just use a while loop
    }
    return sc.nextInt();
}

我所做的改变:

  • 使用hasNextInt,因此您不必使用例外
  • 添加了sc.nextLine();(问题的根源)
  • 而不是递归,只是做一个while循环(为什么你可以简单循环时递归?)
  • 消除临时变量
  • 让它更具可读性(IMO)

答案 1 :(得分:1)

问题

Scanner.nextInt()有能力抛出3个例外:

1- InputMismatchException:当下一个项目不是int时抛出。
2- NoSuchElementException:当没有下一个东西时。
3- IllegalStateException:如果Scanner已关闭。

因此,当您输入非法值(例如“abc”)时,顶部代码会执行此操作:

取“abc”并尝试将其转换为int。 (nextInt())。因为“abc”不是数字,所以它无法转换,并抛出InputMismatchException。但是,由于方法没有成功完成,“abc”将作为下一个要读取的项目。因为抛出了异常,所以运行catch块中的代码。它打印出“你必须输入一个整数”。然后它再次调用自己,传递自己message。然后它会初始化returnval并从第一次运行中打印出相同的message,因为您再次将它传递给自己。然后输入try块,因为“abc”未成功读取并留在那里,扫描仪会读取“abc”并尝试再次将其转换为int。当然,这不起作用,循环再次开始。

解决方案

现在您知道您的问题是什么,您可以找到解决方案。我认为最优雅的方法是使用Scanner方法hasNextInt()。这将返回boolean,告知您是否可以将要阅读的下一个项目转换为int。例如,如果下一个项目是“abc”,则该方法将返回false。对于下一个项目“1”,该方法将返回true。因此,如果您像这样修改代码,它应该可以工作:

public static int inputInt(String message) {                                            
    int returnval = 0;
    System.out.println(message);
    while(!sc.hasNextInt()) {
        sc.nextLine();
        System.out.println("You must enter an integer.");
    }
    returnval = sc.nextInt();
    return returnval;
}

此代码的作用:

1-初始化returnval并打印出message
2-只要扫描仪没有int可读,就进入while循环。有效地“等待”下一个int输入。
3-一旦有int读取,它将读取int并将值保存在returnval中。
4-它将returnval返回给调用者。

(缓慢而稳定地赢得比赛,哈哈。我似乎总是很慢的回答。也许是因为我写小小说作为答案....;)