Почему строка внутри метода println отображается дважды?

Почему в следующем коде строка внутри метода println отображается дважды. Что мне делать, чтобы отображать сообщение один раз за итерацию?

package practicejava;

public class Query {

    public static void main(String[] args) throws java.io.IOException {
        System.out.println("Guess a capital letter Character");
        while ((char) System.in.read() != 'S') {
            System.out.println("wrong.guess again to finish the program");
        }

    }
}

person Tushar Mia    schedule 15.12.2018    source источник
comment
@Tushar Mia: Что мне делать, когда кто-то отвечает на мой вопрос?   -  person Nicholas K    schedule 16.12.2018


Ответы (3)


Когда пользователь вводит символы консоли, для подтверждения того, что его ввод готов для передачи в приложение, он нажимает клавишу enter. Но консоль не передает только предоставленные символы, она также добавляет во входной поток (System.in) зависимую от ОС строку символ(ы) разделителя после него. Некоторые ОС используют \r или \n (это отдельные символы, \x — это просто обозначение для их представления), другие, такие как Windows, используют последовательность \r\n (два символа) в качестве разделителя строк.

Теперь эти дополнительные символы также читаются System.in.read() и, поскольку они не равны S, System.out.println("wrong.guess again to finish the program"); выполняется дополнительное время.

Чтобы избежать таких проблем, вместо работы с необработанными данными через System.in.read() рассмотрите возможность использования классов, предназначенных для облегчения нашей жизни, таких как java.util.Scanner

Scanner sc = new Scanner(System.in);
System.out.println("Guess a capital letter Character");
String response = sc.nextLine();
while(!response.equals("S")){
     System.out.print("incorrect data, please try again: ");
     response = sc.nextLine();
}
person Pshemo    schedule 15.12.2018
comment
Безопаснее было бы while(sc.hasNextLine() && !(response = sc.nextLine()).equals("S")). В противном случае ctrl-D в Linux или ctrl-Z в Windows приведет к бесконечному циклу. - person DodgyCodeException; 21.12.2018

Это потому, что первый символ, который вы читаете, — это введенная вами буква, а затем есть второй цикл, где символ — это возврат строки.

Например, на моей Linux-машине, если я ввожу «E», а затем нажимаю «Ввод», первый цикл обрабатывает символ 69 «E», а затем есть второй цикл для обработки возврата каретки (символ 10).

person David Raluy    schedule 15.12.2018

Что вы можете сделать, так это использовать Scanner, чтобы получить ввод пользователя:

package practicejava;

import java.util.Scanner;

public class Query {

    public static void main(String[] args) throws java.io.IOException {
        Scanner s = new Scanner(System.in);
        char c;

        do {
            System.out.println("Guess a capital letter Character");

            c = s.next().charAt(0);

            if (c != 's') {
                System.out.println("Wrong! Guess again to finish the program.");
            }
        } while(c != 's');
    }
}

s.next() получит ввод от пользователя в виде строки, а s.next().charAt(0) вернет первый символ в этой строке.

person Omari Celestine    schedule 15.12.2018