21

我正在使用以下代码:

while (invalidInput)
{
    // ask the user to specify a number to update the times by
    System.out.print("Specify an integer between 0 and 5: ");

    if (in.hasNextInt())
    {
        // get the update value
        updateValue = in.nextInt();

        // check to see if it was within range
        if (updateValue >= 0 && updateValue <= 5) 
        { 
            invalidInput = false; 
        } 
        else 
        {
            System.out.println("You have not entered a number between 0 and 5. Try again.");
        }
    } else
    {
        System.out.println("You have entered an invalid input. Try again.");
    }
}

但是,如果我输入“w”,它会告诉我“您输入了无效的输入。再试一次。” 然后它将进入一个无限循环,显示文本“指定 0 到 5 之间的整数:您输入的输入无效。再试一次。”

为什么会这样?程序是否应该等待用户输入并在每次到达语句时按回车:

if (in.hasNextInt())
4

4 回答 4

27

在最后一个else块中,您需要清除扫描仪中的“w”或其他无效输入。您可以通过调用next()Scanner 并忽略其返回值来丢弃无效输入来做到这一点,如下所示:

else
{
      System.out.println("You have entered an invalid input. Try again.");
      in.next();
}
于 2009-11-25T02:47:27.907 回答
11

问题是您没有Scanner超越有问题的输入。从hasNextInt()文档:

返回true此扫描器输入中的下一个标记是否可以int使用该方法解释为默认基数中的值nextInt()扫描仪不会超过任何输入。

这适用于所有hasNextXXX()方法:它们返回trueor false,而不推进Scanner.

这是一个片段来说明问题:

    String input = "1 2 3 oops 4 5 6";
    Scanner sc = new Scanner(input);
    while (sc.hasNext()) {
        if (sc.hasNextInt()) {
            int num = sc.nextInt();
            System.out.println("Got " + num);
        } else {
            System.out.println("int, please!");
            //sc.next(); // uncomment to fix!
        }
    }

你会发现这个程序会进入死循环,int, please!反复询问。

如果您取消注释该sc.next()语句,那么它将Scanner越过失败的令牌hasNextInt()。然后程序将打印:

Got 1
Got 2
Got 3
int, please!
Got 4
Got 5
Got 6

失败的检查不会跳过输入的事实hasNextXXX()是有意的:它允许您在必要时对该令牌执行额外的检查。这里有一个例子来说明:

    String input = " 1 true foo 2 false bar 3 ";
    Scanner sc = new Scanner(input);
    while (sc.hasNext()) {
        if (sc.hasNextInt()) {
            System.out.println("(int) " + sc.nextInt());
        } else if (sc.hasNextBoolean()) {
            System.out.println("(boolean) " + sc.nextBoolean());
        } else {
            System.out.println(sc.next());
        }
    }

如果你运行这个程序,它将输出以下内容:

(int) 1
(boolean) true
foo
(int) 2
(boolean) false
bar
(int) 3
于 2010-05-04T05:20:00.803 回答
4

Ben S. 关于非阻塞调用的声明是错误的:

此外, hasNextInt() 不会阻塞。这是非阻塞检查,以查看未来的下一个调用是否可以在没有阻塞的情况下获得输入。

...尽管我确实认识到该文档很容易被误读以给出此意见,并且名称本身暗示它将用于此目的。相关报价,重点补充:

next() 和 hasNext() 方法及其原始类型的伴随方法(例如 nextInt() 和 hasNextInt())首先跳过与分隔符模式匹配的任何输入,然后尝试返回下一个标记。hasNext 和 next 方法都可能阻塞等待进一步的输入。hasNext 方法是否阻塞与其关联的 next 方法是否会阻塞没有关系。

可以肯定的是,这是一个微妙的点。无论说“ hasNext 和 next 方法”,还是“hasext() 和 next() 都”都暗示了伴随方法的行为不同。但是由于它们符合相同的命名约定(当然还有文档),因此可以合理地期望它们的行为相同,并且hasNext() 明确表示它可以阻塞。

元注释:这可能是对不正确帖子的评论,但似乎作为新用户,我只能发布此答案(或编辑似乎更适合文体更改的 wiki,而不是实质更改)。

于 2011-03-22T18:48:26.090 回答
2

标志变量太容易出错而无法使用。改为使用带有注释的显式循环控制。此外,hasNextInt()不阻塞。这是一个非阻塞检查,看看未来的next调用是否可以在没有阻塞的情况下获得输入。如果要阻止,请使用该nextInt()方法。

// Scanner that will read the integer
final Scanner in = new Scanner(System.in);
int inputInt;
do {  // Loop until we have correct input
    System.out.print("Specify an integer between 0 and 5: ");
    try {
        inputInt = in.nextInt(); // Blocks for user input
        if (inputInt >= 0 && inputInt <= 5)  { 
            break;    // Got valid input, stop looping
        } else {
            System.out.println("You have not entered a number between 0 and 5. Try again.");
            continue; // restart loop, wrong number
         }
    } catch (final InputMismatchException e) {
        System.out.println("You have entered an invalid input. Try again.");
        in.next();    // discard non-int input
        continue;     // restart loop, didn't get an integer input
    }
} while (true);
于 2009-11-25T02:45:04.120 回答