2

I'm working through an example program provided in the Book "Java A Beginnner's Guide (9th Ed.)" by Herbert Schildt. The example reads:

The following program demonstrates read() by reading characters from the console until the user types a period.

The code looks like this:

import java.io.*;

public class ReadChars {

    public static void main(String[] args) throws IOException{

        char c;
        
        BufferedReader br = new BufferedReader(
                new InputStreamReader(System.in, System.console().charset()));
        
        System.out.println("Enter characters, period to quit.");
        
        do {
            c = (char) br.read();
            System.out.println(c);
        } while (c != '.');
    }

}

The example output they provide looks like this:

Enter characters, period to quit.
One Two.
O
n
e

T
w
o
.

It to me suggests that the input was (as described) terminated at the '.' character and then printed to the console.

However, when running the example myself, the output looks more like this:

Enter characters, period to quit.
abcde.fghij<return>
a
b
c
d
e
.

That is, I first have to terminate the input with <return> and only then the characters are printed correctly up to the first '.' character in the input.

I would like to understand what exactly is going on here. I assume it has something to do with the fact that the console input is somehow buffered and only flushed on <return>, but to me this is a bit confusing given the structure of the code, which reads and prints the characters in a do-while loop and should break as soon as a '.' is encountered.

Would someone be able to break down the order of things that are happening that lead to this behavior (i.e. the last output above) in contrast to the example output (i.e. the first output above)?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • 1
    It’s probably that your terminal is buffering until the end of line before it’s available to be read by the Java program – Tim Moore Mar 06 '23 at 09:10
  • 1
    I see no point in wrapping the `InputStreamReader` inside another `BufferedReader` the way it's used here and (as the name suggests) the `BufferedReader` adds another layer of buffering that may or may not cause the behaviour you use. To get "as direct as possible" imput, use the `InputStreamReader` directly (though what Tim Moore suggests could still happen and cause the behaviour even without the `BufferedReader`). – Joachim Sauer Mar 06 '23 at 09:22
  • What @TimMoore describes makes sense and seems to be the explanation. I found two related stackoverflow threads on this topic [here](https://stackoverflow.com/questions/1066318/how-to-read-a-single-char-from-the-console-in-java-as-the-user-types-it) and [here](https://stackoverflow.com/questions/74085055/reading-system-in-character-by-character-without-buffering?rq=1) which might be useful for future reference. – fourleafclover Mar 06 '23 at 10:31
  • That is how Buffered Streams work. They are used for better efficiency where data is read or write from buffer. You have decorated your input stream with buffered stream. So as soon as you start giving inputs, it will be sent to the buffer and once you hit enter, your program will start reading that data from buffer. You might want to explore Scanner class. – CyberMafia Mar 06 '23 at 10:40
  • It seems to go deeper than that @CyberMafia. The same behavior persists if InputStreamReader is not wrapped by BufferedReader, as @JoachimSauer pointed out. So it is rather caused by the buffer settings of the terminal itself (in my case on a Linux system). The buffering behavior of the terminal can be changed using e.g. `stty` as pointed out [here](https://stackoverflow.com/a/6876253/17647337), but it is a change that is probably not required/intended by the authors of the example. – fourleafclover Mar 06 '23 at 11:44

1 Answers1

1

System.in which you are using is buffered under the hood. The input will be send to the program only after you press return.
For this kind of functionality is better to use: Scanner class.

I think the autor of the book did not meant that the input was terminated at the "." character. I think what was entered was One Two.return, in the same way as you did.

fascynacja
  • 1,625
  • 4
  • 17
  • 35