简体   繁体   English

Java:无限循环使用扫描仪 in.hasNextInt()

[英]Java: Infinite loop using Scanner in.hasNextInt()

I am using the following code:我正在使用以下代码:

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.");
    }
}

However, if I enter a 'w' it will tell me "You have entered invalid input. Try Again."但是,如果我输入“w”,它会告诉我“您输入了无效的输入。再试一次。” and then it will go into an infinite loop showing the text "Specify an integer between 0 and 5: You have entered an invalid input. Try again."然后它将 go 进入无限循环,显示文本“在 0 和 5 之间指定 integer:您输入的输入无效。再试一次。”

Why is this happening?为什么会这样? Isn't the program supposed to wait for the user to input and press enter each time it reaches the statement:程序是否应该等待用户输入并在每次到达语句时按回车:

if (in.hasNextInt())

In your last else block, you need to clear the 'w' or other invalid input from the Scanner. 在最后一个else块中,您需要清除扫描仪中的“w”或其他无效输入。 You can do this by calling next() on the Scanner and ignoring its return value to throw away that invalid input, as follows: 您可以通过调用Scanner上的next()并忽略其返回值来丢弃该无效输入来执行此操作,如下所示:

else
{
      System.out.println("You have entered an invalid input. Try again.");
      in.next();
}

The problem was that you did not advance the Scanner past the problematic input. 问题是你没有使Scanner超过有问题的输入。 From hasNextInt() documentation: 来自hasNextInt()文档:

Returns true if the next token in this scanner's input can be interpreted as an int value in the default radix using the nextInt() method. 如果使用nextInt()方法将此扫描器输入中的下一个标记解释为默认基数中的int值,则返回true The scanner does not advance past any input. 扫描仪不会超过任何输入。

This is true of all hasNextXXX() methods: they return true or false , without advancing the Scanner . 所有hasNextXXX()方法都是如此:它们返回truefalse ,而不会推进Scanner

Here's a snippet to illustrate the problem: 这是一个说明问题的片段:

    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!
        }
    }

You will find that this program will go into an infinite loop, asking int, please! 你会发现这个程序会进入无限循环int, please! repeatedly. 反复。

If you uncomment the sc.next() statement, then it will make the Scanner go past the token that fails hasNextInt() . 如果取消注释sc.next()语句,那么它将使Scanner超过hasNextInt()失败的标记。 The program would then print: 然后该程序将打印:

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

The fact that a failed hasNextXXX() check doesn't skip the input is intentional: it allows you to perform additional checks on that token if necessary. 失败的hasNextXXX()检查不会跳过输入这一事实是故意的:它允许您在必要时对该令牌执行其他检查。 Here's an example to illustrate: 这是一个例子来说明:

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

If you run this program, it will output the following: 如果您运行此程序,它将输出以下内容:

(int) 1
(boolean) true
foo
(int) 2
(boolean) false
bar
(int) 3

This statement by Ben S. about the non-blocking call is false: Ben S.关于非阻塞调用的声明是错误的:

Also, hasNextInt() does not block. 此外,hasNextInt()不会阻止。 It's the non-blocking check to see if a future next call could get input without blocking. 这是非阻塞检查,以查看未来的下一个呼叫是否可以在不阻塞的情况下获得输入。

...although I do recognize that the documentation can easily be misread to give this opinion, and the name itself implies it is to be used for this purpose. ...虽然我确实认识到文档很容易被误读以表达这种观点,而名称本身意味着它将被用于此目的。 The relevant quote, with emphasis added: 相关报价,重点补充:

The next() and hasNext() methods and their primitive-type companion methods (such as nextInt() and hasNextInt()) first skip any input that matches the delimiter pattern, and then attempt to return the next token. next()和hasNext()方法及其原始类型的伴随方法(例如nextInt()和hasNextInt())首先跳过与分隔符模式匹配的任何输入,然后尝试返回下一个标记。 Both hasNext and next methods may block waiting for further input. hasNext和next方法都可能阻止等待进一步输入。 Whether a hasNext method blocks has no connection to whether or not its associated next method will block. hasNext方法块是否与其关联的下一个方法是否将阻止无关。

It is a subtle point, to be sure. 可以肯定的是,这是一个微妙的观点。 Either saying "Both the hasNext and next methods", or "Both hasnext() and next()" would have implied that the companion methods would act differently. 无论是说“无论 hasNext和next方法”或“两者hasnext()和next()”会暗示伴侣的方法将采取不同。 But seeing as they conform to the same naming convention (and the documentation, of course), it's reasonable to expect they act the same, and hasNext() clearly says that it can block. 但看到它们符合相同的命名约定(当然还有文档),期望它们的行为相同是合理的,并且hasNext()明确表示它可以阻止。

Meta note: this should probably be a comment to the incorrect post, but it seems that as a new user I can only post this answer (or edit the wiki which seems to be preferred for sytlistic changes, not those of substance). 元注释:这可能应该是对不正确的帖子的评论,但似乎作为一个新用户我只能发布这个答案(或编辑维基似乎是首选的sytlistic变化,而不是实质的那些)。

Flag variables are too error prone to use. 标志变量太容易使用。 Use explicit loop control with comments instead. 使用带注释的显式循环控制。 Also, hasNextInt() does not block. 此外, hasNextInt()不会阻止。 It's the non-blocking check to see if a future next call could get input without blocking. 这是非阻塞检查,以查看未来的next呼叫是否可以在不阻塞的情况next获得输入。 If you want to block, use the nextInt() method. 如果要阻止,请使用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);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM