Почему это пропускает раздел user_input этого кода, если пользователь вводит недопустимый выбор?

Метод getSelection позволяет пользователю вводить число со ссылкой на список команд. Если пользователь вводит правильный номер, код работает без сбоев. Однако, если пользователь вводит недопустимое число, код успешно вызовет метод testSelection и будет правильно работать до тех пор, пока не будет вызван метод getSelection. Когда метод вызывается, он продолжает пропускать строку user_input (в режиме отладки), а затем выдает ошибку отсутствия такого элемента. Я знаю, что это означает, что он получает нулевой указатель, но я не могу заставить код приостанавливаться, чтобы пользователь мог ввести новый выбор.

Я попытался добавить оператор if с помощью scan.hasNext, чтобы убедиться, что пользователь ввел новый выбор, и scan.nextLine, чтобы переместить сканер на новую строку. Я не думаю, что это работает, потому что сканер создается и закрывается при каждом запуске метода. При этом я не могу понять, почему он пропускает ввод второго вызова. Я также попытался заставить метод getSelection вызывать метод, если он действителен, ложен, и чтобы testSelection возвращал false, если ввод не соответствует требованиям.

public static String getSelection() {
        Scanner scan = new Scanner(System.in);
        System.out.println("Please enter selection: ");
        String user_input = scan.next();
        scan.close();
        boolean valid;
        try{
            valid  = testSelection(Integer.parseInt(user_input));
        } catch(NumberFormatException e) {
            valid = testSelection(-1);
        }
        if(valid == true) {
            return user_input;
        }
        return "Error";
    }
    public static boolean testSelection(int i) {
        if(i == -1) {
            System.out.println("Please enter an integer (1-7).");
            getSelection();
        }
        if(i > 7 || i < 1) {
            System.out.println("Invalid Selection");
            getSelection();
        }
        return true;
    }

На выходе должен быть выбор пользователя из списка команд до тех пор, пока не будет введена правильная команда.


person S. Morrison    schedule 22.07.2019    source источник


Ответы (1)


В коде есть несколько вещей, которые можно изменить.

  1. scan.next() выдает NoSuchElementException, если в сканере нечего получить. См. здесь.
  2. Поскольку вы читаете ввод с клавиатуры (который не может быть числом), scan.next() остановится на следующем символе пробела, тогда как scan.nextLine() остановится на следующем символе новой строки.
  3. testSelection(-1) не нужен.
  4. testSelection(int) вызывает getSelection(), открывая вам потенциальные проблемы с рекурсией.
  5. Закрытие сканера закроет базовый поток, в данном случае System.in, что не позволит вам читать из него.

Вот полный рабочий пример получения числа от 1 до 7 с клавиатуры.

import java.util.Scanner;

public class App {

    private static final int INVALID_SELECTION = 0;

    public static void main(String...args) {
        Scanner scanner = new Scanner(System.in);
        int selection = getSelection(scanner);
        System.out.printf("Selection value: %d", selection);
        scanner.close();
    }

    public static int getSelection(Scanner scanner) {
        int selection = INVALID_SELECTION;
        for (int attempt = 0; attempt < 5; attempt++) {
            System.out.println("Enter a number between 1 and 7: ");
            if (scanner.hasNextLine()) {
                String line = scanner.nextLine();
                try {
                    selection = Integer.parseInt(line);
                } catch (final NumberFormatException e) {
                    System.out.printf("The input %s cannot be converted to a number%n", line);
                }
            }
            if (selection < 1 || selection > 7) {
                System.out.println("Input is not valid.");
            } else {
                return selection;
            }
        }
        return INVALID_SELECTION;
    }

}
person geco17    schedule 24.08.2019