Java: бесконечный цикл с использованием сканера.hasNextInt()

Я использую следующий код:

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: Вы ввели недопустимый ввод. Попробовать еще раз."

почему это происходит? Разве программа не должна ждать ввода пользователя и нажимать enter каждый раз, когда она достигает оператора:

if (in.hasNextInt())

4 ответов


В прошлом else блок, вам нужно очистить " w " или другой недопустимый вход от сканера. Вы можете сделать это, позвонив next() на сканере и игнорируя его возвращаемое значение, чтобы выбросить этот недопустимый ввод следующим образом:

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

проблема заключалась в том, что вы не продвигали Scanner мимо проблемного ввода. От hasNextInt() документы:

возвращает true если следующий маркер во вводе этого сканера может быть интерпретирован как int значение по умолчанию radix с помощью nextInt() метод. сканер не проходит мимо какого-либо входа.

это верно для всех hasNextXXX() методы: они возвращаются true или 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

Это утверждение Бена С. о неблокирующем вызове ложно:

кроме того, hasNextInt() не блокирует. Это неблокирующая проверка, чтобы увидеть, может ли будущий следующий вызов получить вход без блокировки.

...хотя я признаю, что документация легко может быть неправильно истолковано, чтобы дать это мнение, и само название подразумевает, что оно должно использоваться для этой цели. Соответствующая цитата с ударением добавлена:

методы next() и hasNext ()и их методы-компаньоны примитивного типа (такие как nextInt () и hasNextInt ()) сначала пропустите все входные данные, соответствующие шаблону разделителя, а затем попытайтесь вернуть следующий токен. оба метода hasNext и next могут блокировать ожидание дальнейшего ввода. не имеет ли блок метода hasNext связи с тем, будет ли его связанный следующий метод блокировать.

Это тонкий момент, чтобы быть уверенным. Либо говоря: "оба the hasNext и next методы", или "оба hasnext () и next ()" подразумевали бы, что сопутствующие методы будут действовать по-разному. Но поскольку они соответствуют одному и тому же соглашению об именах (и документации, конечно), разумно ожидать, что они действуют одинаково, и hasNext() ясно говорит, что может блокировать.

Meta Примечание: это, вероятно, должен быть комментарий к неправильному сообщению, но кажется, что как новый пользователь я могу только опубликуйте этот ответ (или отредактируйте wiki, который, по-видимому, предпочтителен для sytlistic изменений, а не для существа).


переменные флага слишком подвержены ошибкам. Вместо этого используйте явный элемент управления loop с комментариями. Кроме того,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);