Я новичок в программировании на Java, я попробовал образец кода, чтобы получить ввод двухзначного числа и напечатать формулировку этого номера.
public class ReadNumberInWord {
public Integer number;
public ReadNumberInWord() {
Scanner userInput = new Scanner(System.in);
System.out.println("Enter the number to read out : ");
try {
number = userInput.nextInt();
readNumber();
} catch (Exception e) {
System.out.println("Please enter an integer");
new ReadNumberInWord();
}
}
public void readNumber() {
System.out.println("Entered number is : " + number);
int numSize = number.toString().length();
System.out.println("number size is : " + numSize);
switch (numSize) {
case 1:
sizeOne();
break;
case 2:
sizeTwo();
break;
case 3:
sizeThree();
break;
case 4:
sizeFour();
break;
default:
System.out.println("Enter number of four digit or less ");
new ReadNumberInWord();
break;
}
}
private void sizeFour() {
System.out.println("Number in words : " + numberCheck(number.toString()));
}
private void sizeThree() {
String[] sizeThree = number.toString().split("");
System.out.println(sizeThree[0]);
System.out.println(sizeThree[1]);
System.out.println(sizeThree[2]);
for (int i = 0; i <= sizeThree.length - 1; i++) {
System.out.println(sizeThree[i]);
}
System.out.println("Number in words : " + numberCheck(number.toString()));
}
private void sizeTwo() {
String[] sizeTwo = number.toString().split("");
//System.out.println(sizeTwo[0]);
//System.out.println(sizeTwo[1]);
String wordsString1 = "";
ArrayList<String> wordsArray = new ArrayList<String>();
for (int i = 0; i <= sizeTwo.length - 1; i++) {
System.out.println(sizeTwo[i]);
String words = numberCheck(sizeTwo[i]);
wordsArray.add(words);
}
for (String w : wordsArray) {
wordsString1 += w + "\t";
}
System.out.println("Number in words : " + wordsString1);
}
private void sizeOne() {
System.out.println("Number in words : " + numberCheck(number.toString()));
}
public String numberCheck(String numb) {
int num = Integer.parseInt(numb);
switch (num) {
case 0:
return "zero";
case 1:
return "one";
case 2:
return "two";
case 3:
return "three";
case 4:
return "four";
case 5:
return "five";
case 6:
return "six";
case 7:
return "seven";
case 8:
return "eight";
case 9:
return "nine";
case 10:
return "ten";
default:
return "unknown";
}
}
public static void main(String[] args) {
new ReadNumberInWord();
}
}
В приведенном выше коде, если я введу двузначное число как 78, он должен напечатать семь восемь. Но это не работает. Вместо этого я получил исключение. Пожалуйста, помогите мне исправить это.
Трассировка стека - это очень полезные фрагменты информации при отладке, и если вы столкнулись с неожиданным исключением, но не считая трассировки стека, вы игнорируете эту информацию. Если бы вы напечатали трассировку стека для своего исключения, вы бы увидели это:
Enter the number to read out :
78
Entered number is : 78
number size is : 2
Exception in thread "main" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at java.lang.Integer.parseInt(Unknown Source)
at ReadNumberInWord.numberCheck(ReadNumberInWord.java:74)
at ReadNumberInWord.sizeTwo(ReadNumberInWord.java:58)
at ReadNumberInWord.readNumber(ReadNumberInWord.java:26)
at ReadNumberInWord.<init>(ReadNumberInWord.java:13)
at ReadNumberInWord.main(ReadNumberInWord.java:94)
Это ясно показывает, что Integer.parseInt()
, через numberCheck()
, вызывается с пустой строкой ""
для ввода, которая не является допустимым целым числом и заставляет Integer.parseInt()
генерировать исключение, которое вы видите.
Теперь вам нужно выяснить, почему это происходит. Вы знаете, что строка, переданная в parseInt()
поступает непосредственно из параметра numberCheck()
, поэтому означает, что numberCheck()
передается пустой строкой. Поскольку вы знаете, что вход поступает из массива sizeTwo
в sizeTwo()
, хорошим началом было бы распечатать содержимое этого массива:
System.out.println(Arrays.toString(sizeTwo));
Сделав это, вы увидите:
[ , 7, 8 ]
Этот первый пустой элемент является подсказкой. Использование split таким образом не совсем корректно, технически строка ввода начинается с "пустой" строки, и вы получаете ее обратно (например, расщепление ":7:8"
on :
. Вам придется либо сделать numberCheck()
игнорировать пустые строки, либо найти другой способ разделить строку на цифры. Первая - это бандажная помощь по первопричине проблемы (помните: это не ваше фактическое намерение включать любые пустые строки в список цифр), поэтому мы сосредоточимся на последнем.
Один из вариантов - преобразовать число в String
(пропустить String[]
вещь), а затем массив char
, например:
char[] digits = number.toString().toCharArray();
Затем вы можете работать с char
вместо String
. Другой вариант - использовать substring()
в вашем цикле, например:
String numberstr = number.toString();
for (int n = 0; n < numberstr.length(); ++ n) {
String digit = number.substring(n, 1);
...
}
Конечно, наличие этого среднего человека на самом деле не обязательно, и вы могли бы просто сделать это с помощью арифметики:
for (int n = (int)Math.log10(number); n >= 0; -- n) {
int digit = (number / (int)Math.pow(10, n)) % 10;
System.out.println(digit);
}
Или наоборот, но не полагаясь на вычисления с плавающей запятой:
int temp = number;
while (temp) {
digit = temp % 10;
temp /= 10;
System.out.println(digit);
}
Ваш код может быть очищен и значительно упрощен многими другими способами (например, как намекнул Ричард Мискин в комментарии, действительно ли вам нужен синтаксический int
?), Но я думаю, что вышеописанное охватывает корень вашей непосредственной проблемы,
Что касается самой обработки ошибок, я рекомендую просто использовать Scanner.next()
для чтения строки, тогда вы можете использовать Integer.parseInt()
для ее синтаксического анализа, и если вы увидите NumberFormatException
, спросите еще раз. Это будет подходящим использованием исключения, а использование next()
а не nextInt()
вытащит токен из потока, даже если это недопустимый int (позволяющий продолжить запрос для ввода). Например:
Scanner userInput = new Scanner(System.in);
System.out.println("Enter the number to read out : ");
while (true) {
try {
number = Integer.parseInt(userInput.next());
break;
} catch (NumberFormatException x) {
System.out.println("Please enter a valid integer");
}
};
Обратите внимание на несколько ключевых концепций:
NumberFormatException
, а не Exception
). Имеет смысл, потому что: NumberFormatException - единственная проблема, с которой мы пытаемся справиться.Ваша текущая реализация устанавливает рекурсивный стек и имеет несколько других проблем.
Проблема заключается в следующем:
String[] sizeTwo=number.toString().split("");
когда число равно "78", оно генерирует массив ["", "7", "8"] вместо ["7", "8"]. Вы должны разделить строку на цифры по-разному (или игнорировать первый токен, который всегда является пустой строкой).
split (..) принимает регулярное выражение, которое определяет, какие шаблоны следует рассматривать как разделители токенов. В вашем случае я нашел следующее regex полезным:
String[] sizeTwo=number.toString().split("(?<=\\d)(?=\\d)");
Это требует, чтобы разделитель представлял собой пустую строку, предшествующую и сопровождаемую цифрой (с использованием функции, называемой положительным lookbehind и положительным взглядом)
Кажется немного странным, что вы читаете символы с терминала в виде Integer
а затем должны прыгать через обручи, чтобы преобразовать его в массив символов для дальнейшей обработки. Логику можно упростить, прочитав в String
, подтвердив, что String
соответствует вашему требованию, а затем обрабатывает каждый символ из String
.
Есть еще несколько изменений, которые я бы сделал:
number
не должен быть переменной-членом, вы можете просто передать его как параметр для каждого вызова метода,String
в целые числа для оператора switch, если вы используете toCharArray()
. Вот пример, который работает со String
а не с Integer
.
import java.util.Scanner;
public class ReadNumberInWord {
public ReadNumberInWord() {
final Scanner userInput = new Scanner(System.in);
System.out.println("Enter the number to read out : ");
boolean success = false;
// Keep looping until the correct input is supplied.
while (!success) {
final String number = userInput.nextLine();
if (validNumber(number)) {
readNumber(number);
success = true;
}
}
}
/**
* @param number
* the String to check.
* @return <code>true</code> if and only if number is less than 5 characters
* long and can be parsed as an integer.
*/
private boolean validNumber(final String number) {
boolean returnValue = false;
try {
Integer.parseInt(number);
if (number.length() <= 4) {
returnValue = true;
} else {
System.out.println("Enter number of four digit or less ");
}
} catch (final NumberFormatException e) {
System.out.println("Please enter an integer");
}
return returnValue;
}
/**
* When supplied a String that represents an integer this method writes out
* each digit as a word to stdout.
*
* @param number
* a String that represents an integer
*/
public void readNumber(final String number) {
System.out.println("Entered number is : " + number);
final int numSize = number.length();
System.out.println("number size is : " + numSize);
final char[] chars = number.toCharArray();
for (int i = 0; i < chars.length; i++) {
System.out.print(numberCheck(chars[i]));
if (i < chars.length - 1) {
System.out.print('\t');
} else {
System.out.println();
}
}
}
/**
* @param num
* a character that represents one of the numbers 0-9
* @return the word representing the supplied number e.g. zero, one etc
*/
public String numberCheck(final char num) {
switch (num) {
case '0':
return "zero";
case '1':
return "one";
case '2':
return "two";
case '3':
return "three";
case '4':
return "four";
case '5':
return "five";
case '6':
return "six";
case '7':
return "seven";
case '8':
return "eight";
case '9':
return "nine";
default:
return "unknown";
}
}
public static void main(final String[] args) {
new ReadNumberInWord();
}
}