Почему мой метод вызывается 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), оставляя вам новый буфер при повторном вызове метода.

Другие вопросы по тегам