Как заставить сканер отбрасывать исключения при вводе неправильного типа?

Вот пример кода:

import java.util.Scanner;
class In
{
    public static void main (String[]arg) 
    {
    Scanner in = new Scanner (System.in) ;
    System.out.println ("how many are invading?") ;
    int a = in.nextInt() ; 
    System.out.println (a) ; 
    } 
}

Если я запустил программу и присвоил ей int как 4, тогда все будет хорошо.

С другой стороны, если я отвечу too many, он не смеется над моей забавной шуткой. Вместо этого я получаю это (как и ожидалось):

Exception in thread "main" java.util.InputMismatchException
    at java.util.Scanner.throwFor(Scanner.java:819)
    at java.util.Scanner.next(Scanner.java:1431)
    at java.util.Scanner.nextInt(Scanner.java:2040)
    at java.util.Scanner.nextInt(Scanner.java:2000)
    at In.main(In.java:9)

Есть ли способ заставить игнорировать записи, которые не являются ints или re prompt, с помощью "Сколько вторжений?" Я хотел бы знать, как это сделать.

Ответ 1

Вы можете использовать один из многих методов hasNext*, которые Scanner имеет для предварительной проверки.

    if (in.hasNextInt()) {
        int a = in.nextInt() ; 
        System.out.println(a);
    } else {
        System.out.println("Sorry, couldn't understand you!");
    }

Это предотвращает даже отбрасывание InputMismatchException, потому что вы всегда убедитесь, что оно будет соответствовать, прежде чем вы его прочитаете.


java.util.Scanner API

  • boolean hasNextInt(): Возвращает true, если следующий токен в этом входе сканера может быть интерпретирован как значение int в базе данных по умолчанию с использованием метода nextInt(). Сканер не продвигается через какой-либо вход.

  • String nextLine(): Адаптирует этот сканер к текущей строке и возвращает пропущенный вход.

Имейте в виду разделы, выделенные жирным шрифтом. hasNextInt() не проходит мимо ввода. Если он возвращает true, вы можете продвинуть сканер, вызвав nextInt(), который не будет бросать InputMismatchException.

Если он возвращает false, вам нужно пропустить "мусор". Самый простой способ сделать это - просто вызвать nextLine(), возможно, дважды, но хотя бы один раз.

Зачем вам нужно выполнить nextLine() два раза: предположим, что это введенный ввод:

42[enter]
too many![enter]
0[enter]

Скажем, сканер находится в начале этого ввода.

  • hasNextInt() истинно, nextInt() возвращает 42; сканер теперь находится непосредственно перед первым [enter].
  • hasNextInt() false, nextLine() возвращает пустую строку, второй nextLine() возвращает "too many!"; сканер теперь сразу после второго [enter].
  • hasNextInt() истинно, nextInt() возвращает 0; сканер теперь находится непосредственно перед третьим [enter].

Вот пример объединения некоторых из этих вещей. Вы можете поэкспериментировать с ним, чтобы изучить, как работает Scanner.

        Scanner in = new Scanner (System.in) ;
        System.out.println("Age?");
        while (!in.hasNextInt()) {
            in.next(); // What happens if you use nextLine() instead?
        }
        int age = in.nextInt();
        in.nextLine(); // What happens if you remove this statement?

        System.out.println("Name?");
        String name = in.nextLine();

        System.out.format("[%s] is %d years old", name, age);

Скажем, что вход:

He is probably close to 100 now...[enter]
Elvis, of course[enter]

Тогда последняя строка вывода:

[Elvis, of course] is 100 years old

Ответ 2

В общем, мне действительно очень не нравится использование одного и того же вызова библиотеки для чтения и разбора. Языковые библиотеки кажутся очень негибкими и часто просто не могут быть согнуты по вашему желанию.

Первый шаг, который извлекает данные из System.in, не должен быть неудачным, поэтому прочитайте его как строку в переменной, а затем преобразуйте эту строковую переменную в int. Если преобразование завершается неудачно, отлично - напечатайте свою ошибку и продолжайте.

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

Ответ 3

Всегда полезно, чтобы ваше приложение выдавало ошибку при возникновении ошибки, противоположной способам ее предотвращения.

Один из вариантов заключается в том, чтобы обернуть код внутри блока try {...} catch {...} для InputMismatchException. Вы также можете обернуть код внутри цикла while, чтобы запрос Scanner продолжал до тех пор, пока не будет выполнено определенное условие.