Вот фрагмент вашего кода, на который я собираюсь взглянуть:
String s = input.next();
numA = Double.parseDouble(s);
operator = input.next().charAt(0);
numB = input.nextDouble();
if (/* Some condition */) {
// Calculate answer
} else {
System.out.println("error input like for an example '10' enter '+' enter '10'");
}
Прежде всего, пара нюансов: Java - это не C. Вам не нужно объявлять все свои переменные вначало вашего кода блоков.numA
, numB
и operator
никогда не используются вне этого бита кода, поэтому имеет смысл также объявить их здесь.
Вы также используете input.next()
с Double.parseDouble()
один раз, затем input.nextDouble()
в следующий раз.Придерживайтесь одного или другого, это облегчит отладку, если что-то не работает должным образом.
И, наконец, что произойдет, если кто-то введет 10 +1 0
?Ошибка игнорируется, потому что 1
выбирается как часть строки operator
и затем удаляется charAt(0)
.Более гибкий метод синтаксического анализа здесь будет состоять в том, чтобы сначала получить все данные String
, а затем проверить length == 1
перед вызовом charAt(0)
.
double numA = input.nextDouble();
String operatorString = input.next();
char operator;
if (operatorString.length() == 1) {
operator = operatorString.charAt(0);
} else {
// Handle error
}
double numB = input.nextDouble();
if (/* Some condition */) {
// Calculate answer
} else {
System.out.println("error input like for an example '10' enter '+' enter '10'");
}
На ваш вопрос: как мы можем обнаружить неверный ввод??Взгляните на документацию для Scanner#nextDouble()
(выделено мной):
public double nextDouble()
Сканирует следующий токен ввода как двойной. Этот метод выдает InputMismatchException
, если следующий токен не может быть преобразован в действительное двойное значение. Если преобразование выполнено успешно, сканер продвигается после соответствующего ввода.
Итак, мы знаем, что nextDouble()
может обнаружить неправильный ввод для нас.Он делает это в форме исключения, которое мы можем прослушивать (или catch ), используя оператор try ... catch
:
try {
double numA = input.nextDouble();
} catch (InputMismatchException e) {
System.err.printf("Invalid input! Expected number, found '%s'.\n", input.next());
}
Мы могли бы расширитьэто и обернуть весь раздел кода в один try ... catch
, но тогда пользователю придется начать заново, если они допустят одну ошибку.Более удобное решение было бы следующим:
double numA;
while (1) {
try {
numA = input.nextDouble();
break;
} catch (InputMismatchException e) {
System.err.printf("Invalid input, try again! Expected number, found '%s'.\n", input.next());
}
}
Обратите внимание, что даже если вы не печатаете его, вызов input.next()
необходим для предотвращения бесконечного цикла.
Теперь нам нужно сделать что-то похожее для operator
:
char operator;
while (1) {
String operatorString;
try {
operatorString = input.next();
if (operatorString.length() != 1) {
throw new InputMismatchException();
}
operator = operatorString.charAt(0);
break;
} catch (InputMismatchException e) {
System.err.printf("Invalid input, try again! Expected character, found '%s'.\n", operatorString);
}
}
Это похоже на предыдущий фрагмент для числа - давайте попробуем преобразовать часть общего кода здесь в метод:
@FunctionalInterface
public interface ScannerGetter<T> {
T apply() throws InputMismatchException;
}
public <T> T getValueFromScanner(ScannerGetter<T> getter, String type) {
while(1) {
try {
return getter.apply();
} catch (InputMismatchException e) {
System.err.printf("Invalid input, try again! Expected %s.");
}
}
}
В этих нескольких строках много чего происходит.Первая часть объявляет функциональный интерфейс - это в основном пользовательский тип лямбда-функции.Мы вернемся к этому чуть позже.
Сам метод (getValueFromScanner()
) является универсальным методом .Это позволяет нам использовать один и тот же метод с разными типами вместо универсального параметра (T
), не дублируя его.
Вот как вы можете использовать вышеуказанный метод для полученияВаши три входа:
double numA = this.<Double>getValueFromScanner(() -> input.nextDouble(), "number");
char operator = this.<Char>getValueFromScanner(() -> {
operatorString = input.next();
if (operatorString.length() != 1) {
throw new InputMismatchException();
}
return operatorString.charAt(0);
}, "operator");
double numB = this.<Double>getValueFromScanner(() -> input.nextDouble(), "number");
// Once your code gets here, all three variables will have valid values.