15

I am new to Java and learning it. I was trying out a code to actually see how the for-each loop works in Java. But I faced a problem regarding that. My code is simple :

class ForEach
{
public static void main(String[] args) throws java.io.IOException
{
    char[] array = new char[10];

    for(int i = 0; i < 10; i++)
    {
        System.out.println("Enter Character " + i);
        array[i] = (char)System.in.read();
    }

    System.out.println("Displaying characters in array : ");

    for(char i : array)
    {
        System.out.println(i);
    }
}
}

but the output is awkward. I am sure something is wrong with my code. I can't just find it. The output of this code is :

Enter Character 0
a
Enter Character 1
Enter Character 2
Enter Character 3
b
Enter Character 4
Enter Character 5
Enter Character 6
c
Enter Character 7
Enter Character 8
Enter Character 9
d
Displaying characters in array :
a


b


c


d

I do not understand why is the for loop running thrice before it takes another input from user?

Any help? Thank you in advance.

Sajib Acharya
  • 1,448
  • 3
  • 28
  • 49

2 Answers2

27

I'm assuming you're on Windows, because this behavior seems about right for Windows.

When you enter a character, you do something like this:

  1. Press a
  2. Press return

Step 2 passes a line separator sequence that indicates to the input console that you have pressed enter, which tells the console that you have finished entering this line of input. So the console passes the entire line to your program.

This line separator sequence on Windows is made up of the carriage return character '\r' followed by the newline character '\n'. So your line is really "a\r\n".

What System.in.read() does is read a single byte from the input console. As the characters you input all fit into a single byte, what your program does is consumes the inputted characters one by one, so it's something like this:

Output: Enter Character 0
> User inputs: "a\r\n" // You only entered 'a', the other two characters are from the enter key
array[0] = System.in.next(); // sets array[0] to 'a', "\r\n" are still "waiting" on the input stream

Output: Enter Character 1
> String "\r\n" is still on input, so read from those:
array[1] = System.in.next(); // sets array[1] to '\r', "\n" is still "waiting"

Output: Enter Character 2
> String "\n" is still on input, so read from that
array[2] = System.in.next(); // sets array[2] to '\n', input source is now empty

Output: Enter Character 3
> Nothing is waiting on the input stream, so program waits for user input

... and so on

What you want to do is make a Scanner, and read an entire line at once, so the only character you process is the content you entered:

Scanner scanner = new Scanner(System.in); // Creates a new scanner that reads from System.in
String line = scanner.nextLine(); // Reads an entire line from console, **not including newline breaks at the end of a line**
// use line.charAt(i) to get individual characters, or use line.toCharArray() to get the string's backing char[]

If you were to print the integer values of each of the elements in your array, you'd actually see numbers where your console outputs blank lines. These numbers are the ASCII numerical equivalents to the '\r' and '\n' characters.

Interestingly, I believe that if you were run this on a *nix system you'd only skip a single line instead of two. This is because *nix systems use just '\n' as their line separator, so you'd only have a single extra character at the end of your line.

Also, I'm not entirely sure why your console is outputting a line for both '\r' and '\n'; could be that Java breaks lines for both characters internally, while Windows does not. So you might even get different results if you were to try to run this in a Windows shell.

awksp
  • 11,292
  • 4
  • 35
  • 44
  • Just to be curious, what if at the very beginning, I give the input as `abcdefghij` will that take all the 10 characters one by one into my character type array and leave away the `\r\n` which is at the end of my input line because there is no space left in the array and also because there won't be any more iterations? – Sajib Acharya May 18 '14 at 09:13
  • That sounds about right; the limiting factor in this case would be the array size, not the blocking behavior of `System.in`. But don't take my word for it -- try it yourself! – awksp May 18 '14 at 09:15
1

From the Java API:

Reads the next byte of data from the input stream.

What happens is when you type a followed by a newline, there are actually three bytes to read (I'm guessing a followed by carriage return and newline). Hence, the input you provide is enough to keep read() running for three iterations.

I recommend you to use Scanner for input reading instead.

kviiri
  • 3,102
  • 1
  • 18
  • 30
  • Standard input is line buffered by default, so is this responsible for the two extra inputs which is resulting two extra iterations? I'm just curious to know. – Sajib Acharya May 18 '14 at 08:59
  • @SajibAcharya, yeah. And `read()` reads the line break characters just like any byte. – kviiri May 18 '14 at 09:33