#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
оператор никогда не выполняется 🙁