Вопрос-ответ

How to handle infinite loop caused by invalid input (InputMismatchException) using Scanner

Как обрабатывать бесконечный цикл, вызванный недопустимым вводом (InputMismatchException), с помощью сканера

Итак, я застрял с этим фрагментом кода:

import java.util.InputMismatchException;
import java.util.Scanner;

public class ConsoleReader {

Scanner reader;

public ConsoleReader() {
reader = new Scanner(System.in);
//reader.useDelimiter(System.getProperty("line.separator"));
}

public int readInt(String msg) {
int num = 0;
boolean loop = true;

while (loop) {
try {
System.out.println(msg);
num = reader.nextInt();

loop = false;
} catch (InputMismatchException e) {
System.out.println("Invalid value!");
}
}
return num;
}
}

и вот мой вывод:


Вставьте целое число:
Недопустимое значение!
Вставьте целое число:
Недопустимое значение!
...


Переведено автоматически
Ответ 1

Согласно javadoc для Scanner:


Когда сканер выдает исключение InputMismatchException, сканер не передает токен, вызвавший исключение, так что его можно извлечь или пропустить каким-либо другим методом.


Это означает, что если следующий токен не является int, он выбрасывает InputMismatchException, но токен остается там. Итак, на следующей итерации цикла reader.nextInt() снова считывает тот же токен и снова создает исключение. Что вам нужно, так это использовать его. Добавьте reader.next() внутри вашегоcatch, чтобы использовать токен, который недействителен и должен быть удален.

...
} catch (InputMismatchException e) {
System.out.println("Invalid value!");
reader.next(); // this consumes the invalid token
}
Ответ 2

Что я бы сделал, так это прочитал всю строку с помощью Scanner.nextLine() . Затем создайте другой сканер, который считывает возвращенную строку.

String line = reader.nextLine();
Scanner sc = new Scanner(line);

Это сделало бы ваш пример функции примерно таким:

  public int readInt(String msg) {
int num = 0;
boolean loop = true;

while (loop) {
try {
System.out.println(msg);
String line = reader.nextLine();
Scanner sc = new Scanner(line);
num = sc.nextInt();
loop = false;
} catch (InputMismatchException e) {
System.out.println("Invalid value!");

}
}
return num;
}

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

Ответ 3

Защита вашего while-do - это переменная 'loop'.

Само исключение, генерируемое до того, как ваш код достигнет цикла присваивания = false; Если быть точным, исключение генерируется в предыдущем операторе, который является num = reader.nextInt();

При возникновении исключения значение переменной 'loop' равно 'true', но ваш код переходит к блоку catch, а затем повторяет while-do . Это while-do никогда не остановится, потому что следующая итерация снова выдаст исключение, снова перейдет к блоку перехвата и так далее.

Чтобы завершить это while-do , вам нужно защитить свой while-do другой логической вещью, такой как :


  1. Выход, когда считыватель получает символ, отличный от int

  2. Выход при EOF

Это можно сделать в блоке catch или некоторых других строках. Но точное решение зависит от ваших спецификаций.

Ответ 4

Вы также можете попробовать это:

   public int readInt(String msg) {
int num = 0;
try {
System.out.println(msg);
num = (new Scanner(System.in)).nextInt();
} catch (InputMismatchException e) {
System.out.println("Invalid value!");
num = readInt(msg);
}
return num;
}
java