Multiple Iteration with System.in.read() - java

I am learning some basic IO right now and I decided to play around with some code, I wrote the following:
do{
System.out.print("Enter a char: ");
char x = (char)System.in.read();
if(x == 'q'){
break;
}
}while(true);
When I run this code and provide an incorrect input (ie anything that's not 'q') I get multiple prompts instead of 1.
Enter a char: s
Enter a char: Enter a char: Enter a char:
The same does not occur when using the Scanner object to read data.
Why is this occurring?
Thanks for any help.

char x = (char)System.in.read(); This line reads your inputs char by char. When you enter one char s and then press enter, actually you have two chars as follows;
s
\n (new line char, because you press enter)
Let's say you enter ab and then press enter, it means that you have 3 chars;
a
b
\n
So your code reads your input char by char on each iteration, and on each iteration you print Enter a char:.
But as you said that Scanner works just fine with same input. Because when you read input with Scanner.nextLine() you read your whole input as one string.
If you mark your code (inside loop) with breakpoint and debug it, you will see its behavior.

Related

What is the function of nested do-while loop here in this Java guess game program?

I don't understand how the nested do-while loop could discard other characters and why is there a newline syntax. Could some one explains it, many thanks.
public class guessGame {
public static void main(String[] args) throws java.io.IOException{
char ch, ignore,answer='K';
do {
System.out.println("I'm thinking of a letter between A and Z.");
System.out.print("Can you guess it:");
//read a character
ch=(char) System.in.read();
// ************ here ************
do {
ignore =(char) System.in.read();
} while (ignore != '\n');
// ************ to here ************
if (ch==answer) System.out.println("** Right **");
else {
System.out.print("...Sorry, you're ");
if(ch<answer) System.out.println("too low");
else System.out.println("Too high");
System.out.println("Try again\n");
}
} while (answer !=ch);
}
}
Input from the user until newline char is read and first char from the input is assigned to ch with this line:
ch=(char) System.in.read();
After that, rest of the input user entered is assigned to ignore variable. New line syntax basically tells the program that this is the last char from input stream.
After first char from the input is assigned to ch, code block inside do statement is executed once. If the second char user typed is \n, while statement becomes false and program continues to execute from next line of code. If the second char typed is not newline char, loop continues until newline char.
Why is it needed?
ch=(char) System.in.read();
//user enters ASDF\n
//ch is assigned as A
do {
ignore =(char) System.in.read();//SDF\n is assigned to ignore
} while (ignore != '\n');
If the inner do while above wouldn't exist, the outer loop would automatically assign SDF\n (including newline char) to ch from input stream one by one in every loop and each would be regarded as an answer from the user until input stream has no more chars left.
I don't have enough reputation to reply in the comment.
The code which you has written above will get completed only when you are giving character 'K'. Inner do while is to skip the if-else statement when the character is /n.
Only when you are giving character 'K', the outer do-while will get satisfied and get completed.
For example -
input character is 'A' - It will print sysout statements and once again wait for the new input.
input character is '/n' - It won't print any sysout. But, it will wait for the new input.
input character is 'K' - It will print sysout as right and get completed.
Your program behave in this way (in English):
Step 1 : accept a character followed by an Enter key (the newline character).
Step 2 : if the character input is not answer, return to Step 1
Step 3 : print ** Right **
Now, there are two reasons the do ... while loop you mentioned is there.
First reason, user can type "abcdef" followed by an enter key.
For this case, the program only wants to take the first character 'a' to compare with answer. The rest are to be discarded. The do ... while is there to ignore "bcdef".
Second reason, in certain operating system, all linefeed ('\n') is proceeded by the carriage return ('\r'). For this case, one needs to ignore the carriage return.
public class guessGame {
public static void main(String[] args) throws java.io.IOException{
char ch, ignore,answer='K';
do {
System.out.println("I'm thinking of a letter between A and Z.");
System.out.print("Can you guess it:");
//read a character
ch=(char) System.in.read();
// Case 1 : assume user input "abcdef\n" here
// Case 2 : assume operating system makes user input "a\r\n"
// ************ here ************
do {
ignore =(char) System.in.read();
// Case 1 : "bcdef\n" is read in this loop
// Case 2 : "\r\n" is read in this loop
} while (ignore != '\n');
// Case 1 : "bcdef" is ignored
// Case 2 : "\r" is ignored
// ************ to here ************
if (ch==answer) System.out.println("** Right **");
else {
System.out.print("...Sorry, you're ");
if(ch<answer) System.out.println("too low");
else System.out.println("Too high");
System.out.println("Try again\n");
}
} while (answer !=ch);
}
}

Using scanner in retrieving lines

am stuck with this question
6) Suppose you enter 34.3, the ENTER key, 57.8, the ENTER key, 789, the ENTER key. Analyze the following code.
Scanner scanner = new Scanner(System.in);
int value = scanner.nextDouble();
int doubleValue = scanner.nextInt();
String line = scanner.nextLine();
i know the answer, the line will be equal to '\n' when the last statement is executed but why?
can anyone please explain it for me please?
The Scanner reads as many tokens as necessary to get it's next output and then leaves all of the rest of the tokens there to be examined. nextInt() does not need the newline character so it leaves it in the token stream. When you call nextLine() it looks into the token stream, sees the newline character, and returns that.
Let's break this statement by statement.
Scanner scanner = new Scanner(System.in);
int value = scanner.nextDouble();
The system waits for you to type in the value.
34.3↲
The value is read as 34.3 but is truncated to 34 since it is stored as an integer. Now the next statement is executed.
int doubleValue = scanner.nextInt();
The system waits for you again to type in the value.
57.8↲
The value is read as 57 as you are using scanner.nextInt() and hence, the .8 is ignored. There is however a enter remaining in the buffer.
String line = scanner.nextLine();
The system now waits again for the input, and you type in this. The first new line is the remnant from the previous input.
↲
789↲
The scanner first sees the newline character, so it assumes that the line is terminated. So the value is read as \n
Hope this helps.

Why my method being called 3 times after System.in.read() in loop

I have started to learn Java, wrote couple of very easy things, but there is a thing that I don't understand:
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');
}
Why does the System.out.println prints "Quess the letter" three times after giving a wrong answer. Before giving any answer string is printed only once.
Thanks in advance
Because when you print char and press Enter you produce 3 symbols (on Windows): character, carriage return and line feed:
q\r\n
You can find more details here: http://en.wikipedia.org/wiki/Newline
For your task you may want to use higher level API, e.g. Scanner:
Scanner scanner = new Scanner(System.in);
do {
System.out.println("Guess the letter");
ch = scanner.nextLine().charAt(0);
} while (ch != 'q');
Using System.in directly is probably the wrong thing to do. You'll see that if your character is changed from q to something in Russian, Arabic or Chinese. Reading just one byte is never going to match it. You are just lucky that the bytes read from console in UTF-8 match the character codes for the plain English characters.
The way you are doing it, you are looking at the input as a stream of bytes. And then, as #Sergey Grinev said, you get three characters - the actual character you entered, and the carriage return and line feed that were produce by pressing Enter.
If you want to treat your input as characters, rather than bytes, you should create a BufferedReader or a Scanner backed by System.in. Then you can read a whole line, and it will dispose of the carriage return and linefeed characters for you.
To use a BufferedReader you do something like:
BufferedReader reader = new BufferedReader( InputStreamReader( System.in ) );
And then you can use:
String userInput = reader.readLine();
To use a Scanner, you do something like:
Scanner scanner = new Scanner( System.in );
And then you can use:
String userInput = scanner.nextLine();
In both cases, the result is a String, not a char, so you should be careful - don't compare it using == but using equals(). Or make sure its length is greater than 1 and take its first character using charAt(0).
As has been mentioned, the initial read command takes in 3 characters and holds them in the buffer.
The next time a read command comes around, it first checks the buffer before waiting for a keyboard input. Try entering more than one letter before hitting enter- your method should get called however many characters you entered + 2.
For an even simpler fix:
//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');
this way 'ignore' will cycle through the buffer until it hits the newline character in the buffer (the last one entered via pressing enter in Windows) leaving you with an fresh buffer when the method is called again.

What's wrong with For Loop?

package mygradeloops;
import java.io.IOException;
public class MyGradeLoops {
public static void main(String[] args) throws IOException {
char x = 'A';
for (x='0';x<'9';x++){
System.out.println("Please enter in one of your grades.");
System.in.read();
System.out.println("Keep going!");
}
}
}
This code keeps double printing after the first "grade". Does anyone know why it double prints? Have I done the "For Loop" wrong?
It's "double printing" because when you enter a character by pressing return, you're actually writing two characters: the character you typed, and \n (newline character).
Add a second System.in.read(); call to read the newline character:
for (x='0';x<'9';x++){
System.out.println("Please enter in one of your grades.");
System.in.read(); // your character
System.in.read(); // newline
System.out.println("Keep going!");
}
Also, initializing x to 'A' in not needed, char x; is fine. In fact, it doesn't make sense to use a char in this loop, using an int would be preferred.
The read method for System.in (an InputStream) only reads one byte of data from the input stream. Because you must hit "Enter" to send your input to the stream, you have two characters on the stream - the character you typed plus a newline.
The for loop loops twice, and "double prints" Keep going! and Please enter in one of your grades. because each iteration reads one of the two characters on the stream.
It would be easier to wrap System.in in a InputStreamReader then a BufferedReader or just initialize a Scanner with System.in. With a BufferedReader you can just call readLine(), and with a Scanner you can call nextLine().
Also, it's unclear why you are looping from '0' to '9' with chars. It would be clearer to use an int for a and loop from 0 until 9.

Java method not waiting on BufferedReader input?

I have a BufferedReader waiting for input, but for some reason it doesn't wait for the second read and continues to print my third print statement.
Code:
BufferedReader inFromUser =new BufferedReader(new InputStreamReader(System.in));
char letter,xVal;
int yVal;
System.out.println("Please enter a letter for your word.(a-z)");
letter=(char)inFromUser.read();
System.out.println("Please enter a X location for this piece.(A-J)");
xVal=(char)inFromUser.read();
System.out.println("Please enter a Y location for this piece.(0-9)");
yVal=inFromUser.read();
Example execution goes as follows:
Please enter a letter for your word. //Waits on input here
a
Please enter a X location for this piece. //Doesn't wait here???
Please enter a Y location for this piece.
This is happening because once you press enter after typing a letter, you are also sending the newline character into the stream.
When you call read() the first time it returns the first character as expected. However, when you call read() the second time it will simply read in the newline character that is buffered in the stream, thereby seeming like it skipped over a read instruction.
The solution is to tell the BufferedReader to read the entire line, then fetch the first character from the line:
System.out.println("Please enter a letter for your word.(a-z)");
letter = inFromUser.readLine().charAt(0);
You may also want to improve upon this by doing some validation in case the user simply presses enter without inputting a letter.
The reason why it was not waiting is because xVal=(char)inFromUser.read(); was reading the "\n" from the line letter=(char)inFromUser.read();
So one solution it to add an inFromUser.readLine(); after each prompt:
System.out.println("Please enter a letter for your word.(a-z)");
letter=(char)inFromUser.read();
inFromUser.readLine();
System.out.println("Please enter a X location for this piece.(A-J)");
xVal=(char)inFromUser.read();
inFromUser.readLine();
System.out.println("Please enter a Y location for this piece.(0-9)");
yVal=inFromUser.read();
inFromUser.readLine();
You add a inFromUser.readLine(); after each prompt, so it can read the "\n".

Categories

Resources