Почему мой метод вызывается 3 раза после System.in.read() в цикле
Я начал изучать Java, написал пару очень простых вещей, но есть вещь, которую я не понимаю:
public static void main(String[] args) throws java.io.IOException
{
char ch;
do
{
System.out.println("Quess the letter");
ch = (char) System.in.read();
}
while (ch != 'q');
}
Почему System.out.println
печатает "Quess the letter" три раза после неправильного ответа. Перед предоставлением любого ответа строка печатается только один раз.
заранее спасибо
3 ответа
Потому что, когда вы печатаете char и нажимаете Enter, вы создаете 3 символа (в Windows): символ, возврат каретки и перевод строки:
q\r\n
Вы можете найти более подробную информацию здесь: http://en.wikipedia.org/wiki/Newline
Для вашей задачи вы можете использовать более высокий уровень API, например Scanner
:
Scanner scanner = new Scanner(System.in);
do {
System.out.println("Guess the letter");
ch = scanner.nextLine().charAt(0);
} while (ch != 'q');
С помощью System.in
напрямую, вероятно, неправильно. Вы увидите, что если ваш персонаж изменится с q
к чему-то на русском, арабском или китайском. Чтение только одного байта никогда не будет соответствовать этому. Вам просто повезло, что считанные из консоли байты в UTF-8 соответствуют кодам символов для простых английских символов.
То, как вы это делаете, вы рассматриваете входные данные как поток байтов. И тогда, как сказал @Sergey Grinev, вы получите три символа - фактический введенный вами символ, а также возврат каретки и перевод строки, которые были получены при нажатии Enter.
Если вы хотите обрабатывать ввод как символы, а не как байты, вы должны создать BufferedReader
или Scanner
при поддержке System.in
, Затем вы можете прочитать целую строку, и она избавится от символов возврата каретки и перевода строки.
Использовать BufferedReader
вы делаете что-то вроде:
BufferedReader reader = new BufferedReader( InputStreamReader( System.in ) );
И тогда вы можете использовать:
String userInput = reader.readLine();
Использовать Scanner
Вы делаете что-то вроде:
Scanner scanner = new Scanner( System.in );
И тогда вы можете использовать:
String userInput = scanner.nextLine();
В обоих случаях результатом является String
не char
так что вы должны быть осторожны - не сравнивайте это, используя ==
но используя equals()
, Или убедитесь, что его длина больше 1 и введите первый символ, используя charAt(0)
,
Как уже упоминалось, начальная команда чтения принимает 3 символа и хранит их в буфере.
В следующий раз, когда приходит команда чтения, она сначала проверяет буфер перед ожиданием ввода с клавиатуры. Попробуйте ввести более одной буквы, прежде чем нажать Enter- ваш метод должен вызываться независимо от того, сколько символов вы ввели + 2.
Для еще более простого исправления:
//add char 'ignore' variable to the char declaration
char ch ignore;
//add this do while loop after the "ch = (char) System.in.read();" line
do{
ignore = (char) System.in.read();
} while (ignore != '\n');
таким образом "игнорировать" будет циклически проходить через буфер до тех пор, пока он не достигнет символа новой строки в буфере (последний введенный нажатием клавиши ввода в Windows), оставляя вам новый буфер при повторном вызове метода.