Java Integer.parseInt хочет проанализировать слова, которые уже исчезли

#java

Вопрос:

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

Описание задачи таково:

Пользовательский ввод содержит 2 положительных целых числа, разделенных пробелом. Если пользователь вводит слова, сообщение об ошибке должно указывать пользователю использовать числа, если числа отрицательные или находятся вне диапазона, в сообщении указывается использовать числа 1-3.

Я проверял это, введя два слова «один» и «два», в коде правильно указано вводить цифры. Когда я теперь ввожу целые числа «1» и «2», метод выполняется до конца, но затем возникает исключение:

 Exception in thread "main" java.lang.NumberFormatException: For input string: "one"
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.base/java.lang.Integer.parseInt(Integer.java:652)
at java.base/java.lang.Integer.parseInt(Integer.java:770)
at Scratch.getValidCoordinates(scratch_3.java:21)
at Scratch.main(scratch_3.java:6) 




import java.util.Scanner;

class Scratch {
public static void main(String[] args) {
    getValidCoordinates();
}

public static int[] getValidCoordinates() {
    Scanner scanner = new Scanner(System.in);
    System.out.println("Enter the coordinates: ");
    String[] coordinates = scanner.nextLine().split(" ");

    if (!coordinates[0].matches("(-|\ )?\d ") || !coordinates[1].matches("(-|\ )?\d ")) {
        System.out.println("You should enter numbers!");
        getValidCoordinates();
    }

    int[] numCoordinates = {Integer.parseInt(coordinates[0]), 
Integer.parseInt(coordinates[1])};

    if (numCoordinates[0] > 3 || numCoordinates[0] < 1 || numCoordinates[1] > 3 || 
numCoordinates[1] < 1) {
        System.out.println("Coordinates should be from 1 to 3!");
        getValidCoordinates();
    }

    return numCoordinates;
 }
}
 

Комментарии:

1. Не повторяйтесь. Используйте бесконечный цикл и continue;

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

3. @FedericoklezCulloca не могли бы вы, пожалуйста, уточнить, что вы имеете в виду под возвращением?

4. Просто позвонив getValidCoordinates , вы потеряете все, что возвращает рекурсивный вызов, поэтому вам следует return getValidCoordinates();

Ответ №1:

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

 public static int[] getValidCoordinates() {
    Scanner scanner = new Scanner(System.in);
    System.out.println("Enter the coordinates: ");
    String[] coordinates = scanner.nextLine().split(" ");

    if (!coordinates[0].matches("(-|\ )?\d ")
            || !coordinates[1].matches("(-|\ )?\d ")) {
        System.out.println("You should enter numbers!");
        return getValidCoordinates();
    }

    int[] numCoordinates = { Integer.parseInt(coordinates[0]),
            Integer.parseInt(coordinates[1])
    };

    if (numCoordinates[0] > 3 || numCoordinates[0] < 1
            || numCoordinates[1] > 3 || numCoordinates[1] < 1) {
        System.out.println("Coordinates should be from 1 to 3!");
        return getValidCoordinates();
    }

    return numCoordinates;
}
 

Или с бесконечным циклом, таким как

 public static int[] getValidCoordinates() {
    Scanner scanner = new Scanner(System.in);
    while (true) {
        System.out.println("Enter the coordinates: ");
        String[] coordinates = scanner.nextLine().split(" ");

        if (!coordinates[0].matches("(-|\ )?\d ")
                    || !coordinates[1].matches("(-|\ )?\d ")) {
            System.out.println("You should enter numbers!");
            continue;
        }

        int[] numCoordinates = { Integer.parseInt(coordinates[0]), 
            Integer.parseInt(coordinates[1])
        };

        if (numCoordinates[0] > 3 || numCoordinates[0] < 1
                    || numCoordinates[1] > 3 || numCoordinates[1] < 1) {
            System.out.println("Coordinates should be from 1 to 3!");
            continue;
        }

        return numCoordinates;
    }
}
 

Чтобы еще больше помочь вашему пониманию, рассмотрите следующую тривиальную программу.

 static int recurse(int a) {
    try {
        throw new Exception("A "   a);
    } catch (Exception e) {
        e.printStackTrace();
    }
    if (a < 10) {
        recurse(a   1);
    }
    try {
        throw new Exception("B "   a);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return 1;
}

public static void main(String[] args) {
    recurse(1);
}
 

Обратите внимание, что вы можете четко видеть, как кадр стека растет (и сжимается) по мере того, как функция рекурсивно рассчитывает до 10 (а затем до 1 ).

Комментарии:

1. Спасибо. Итак, верните getValidCoordinates(); вместо только getValidCoordinates(); действительно «сбрасывает» все внутри метода?

2. Нет. Это приводит к тому, что поток программы возвращается вызывающему абоненту. Вместо того, чтобы следовать этому методу.

3. Фрич, не могли бы вы объяснить это немного проще? 🙂

4. Самое простое объяснение — «рекурсия». Исходное выполнение продолжается , когда стековый кадр разматывается рекурсивным возвращением вызова. Ваш исходный код удаляет результат рекурсивного вызова.

5. Почему «один» не печатается, когда я помещаю инструкцию печати для печати координат в свой исходный код прямо перед возвратом? Я имею в виду, где «один» хранится в моем коде? Какую переменную мне нужно распечатать, чтобы увидеть, где находится «один»?

Ответ №2:

Давайте отладим ваш код! Но позвольте мне упростить это с помощью псевдокода:

 void main() {
  coordinates();
}

int[] coordinates() {
  coordinates = nextLine().split(" ");
  if(!coordinates.matches("(-|\ )?\d ")) {
    print("Only numbers are allowed");
    coordinates();
  }

  numberCoordinates = coordinates.toInt();
  if(coordinates.bounds()) {
    print("Out of bounds");
    coordinates();
  }

  return numberCoordinates;
}
 

Давайте «запустим» его:

  • Мы входим one two
  • Он раскалывается, и теперь coordinates = {"one", "two"}
  • Но это не соответствует регулярному выражению, вызывающему другую coordinates() функцию
  • Мы входим 1 2
  • Он разделяется и правильно совпадает
  • Но мы возвращаемся к внешней coordinates() функции, и она продолжается
  • coordinates[0] во внешней coordinates() функции все еще one
  • Функция не останавливается, даже если проверка не удалась, и ваша Integer.parseInt также не выполняется

Я нарисовал для вас схему 🙂 введите описание изображения здесь

Вот и все! Перепишите свою функцию с while помощью — когда ваша проверка завершится неудачно, просто используйте continue ключевое слово, и ваша функция запросит новую строку!

Комментарии:

1. Спасибо вам за эту классную схему! 🙂 Я понимаю… Ну, я думал, что повторный вызов метода «перезагрузит» все. По крайней мере, я так думал, потому что я проверил значения строковых координат[] и int numCoordinates[] с помощью инструкции print и нигде не смог найти «один»

2. @KabraxisLuvos, все в порядке, мы все иногда совершаем ошибки. Программирование-это таинственный лес 😛 Если вы нашли мой ответ полезным, пожалуйста, не забудьте пометить его как «правильный»! Спасибо! 🙂 (Но, если у вас есть какие-либо вопросы, задавайте их здесь! :Р)

3. почему печать координат или координат не выводит «один», если я помещаю его перед своим заявлением о возврате? 🙂

4. @KabraxisLuvos, потому что «один» — это не число 🙂 Когда вы передаете нечисловые значения в консоль, return оператор никогда не выполняется 🙁