3

In the following Java code

Scanner input = new Scanner(System.in);    //Cmd1
int i1,i2;                                 //Cmd2
i1 = input.nextInt();                      //Cmd3
System.out.println("value of i1 is "+ i1); //Cmd4
i2 = input.nextInt();                      //Cmd5
System.out.println("value of i2 is "+ i2); //Cmd6
String s1;                                 //Cmd7
input.nextLine();                          //Cmd8
s1 = input.nextLine();                     //Cmd9
System.out.println("value of s1 is "+ s1); //Cmd10

I got the following output in my console

<myinput> 1
<output>  value of i1 is 1
<myinput> 2
<output>  value of i2 is 2
<myinput> firstString
<output>  value of s1 is firstString

<myinput> kept on waiting for input till i pressed enter key. I tried tab, multiple tab, space but it kept on waiting and didn't move to the next command which is <output> hence i assumed that nextInt waits till it find \n in an input stream before moving onto next command.

Looking at the answers from Scanner is skipping nextLine() after using next() or nextFoo()?, the reason we have to add Cmd8 is because nextInt() keep on reading input till \n, sends input to program and puts \n back in front of input stream. Now when nextLine() in "Cmd8" starts reading it, it finds \n at the starting of input stream without any preceding string, it assumes user didn't enter anything hence takes empty string as input and go to Cmd9.

My doubt here is since nextInt() also reads till \n (implying from my experience that Cmd3 kept on waiting until i pressed enter) why is Cmd5 waiting for my input. It should have also find \n in the beginning of input stream and assume that i didn't enter anything and take empty integer as input (similar to how Cmd8 is behaving). What is happening here?

Garvit Arora
  • 75
  • 1
  • 6
  • 3
    What makes you believe `nextInt()` stops at `\n`? – Tom Dec 28 '20 at 21:10
  • 1
    Please [edit] your question to include the EXACT sequence of keyboard keys you have pressed while running this program. Also include the output you get from your application. – Progman Dec 28 '20 at 21:14
  • 1
    @GarvitArora The line you are entering is "send" to your java application when you pressed `enter`, not before. So when you entering digits for your number these input isn't send to your java application yet, so you java application is still waiting for your first input. – Progman Dec 28 '20 at 21:20
  • @Progman Sorry can you please elaborate. What i understood from your comment is when i press "enter" it "send" my input to program and also creates \n character which is not consumed. But nextInt stops reading at "send" command rather than \n. So the input for nextInt(i2), is technically `\n + ` till "send" , but since it skips whitespaces it only stores . Is this correct understanding? – Garvit Arora Dec 28 '20 at 21:32
  • @GarvitArora What is the question/problem/issue you have? It's difficult to understand what you are trying to ask. Please [edit] your post to add a detailed description of what you are asking. – Progman Dec 28 '20 at 21:34
  • Check the implementations of `nextInt()` and `next()` methods in jdk sources: https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/util/Scanner.java – Elyas Hadizadeh Dec 28 '20 at 22:23

2 Answers2

3

I have analyzed your question with debugging JRE Scanner class methods. When you called nextInt function, Scanner looks current buffer. If there is no available input, started listening to the keyboard until you press Enter key, whole keyboard characters appended to the buffer and tried to match that it is an integer or not. When it is found an integer nextInt returns the value and increments the buffer's position index. Next step, you called the nextInt again, and there is only \n character, then it is discarded and waited for the next integer pattern. Also, the buffer's next character is \n again. When you called nextLine it looks to the buffer and prints an empty line. So second nextLine is starting with empty text.

Maybe it can be confusing. Let's look at the scenario:

Note: Index ^ represents the buffer's reading position.


  1. Step
i1 = input.nextInt();
keyboard = 1 2 {Enter}
buffer = | 1 | 2 | \n |
index  =   ^

returns 12 and the next buffer position is located to \n


  1. Step
i2 = input.nextInt();
keyboard = 3 4 {Enter}
buffer = | 1 | 2 | \n | 3 | 4 | \n |
index  =           ^

returns 34 and the next buffer position is located to second \n


  1. Step
input.nextLine();

Buffer has \n character, so Scanner does not wait for keyboard and returns the value.

buffer = | 1 | 2 | \n | 3 | 4 | \n |
index  =                         ^

returns empty text


  1. Step
s1 = input.nextLine();
keyboard = test {Enter}
buffer = | 1 | 2 | \n | 3 | 4 | \n | t | e | s | t | \n |
index  =                             ^

returns test


ismail durmaz
  • 2,280
  • 1
  • 4
  • 17
1

Note the following excerpt from Scanner#next documentation:

Finds and returns the next complete token from this scanner. A complete token is preceded and followed by input that matches the delimiter pattern.

The default delimiter use by Scanner is \p{javaWhitespace}+ which you can get as follows:

import java.util.Scanner;

public class Main {
    public static void main(String... args) {
        Scanner input = new Scanner(System.in);
        System.out.println(input.delimiter());
    }
}

The following lines of code show how a complete token is found as soon as 10 or hello is found i.e. no matter how many times you press Enter, next(), nextInt() etc. will keep asking for the input until a non-whitespace character is entered. Note: In case of nextInt(), the value 10 is parseable to int but hello is not and therefore InputMismatchException will be thrown.

public class Main {
    public static void main(String... args) {
        System.out.println(Character.isWhitespace('\n'));
        System.out.println("\n\n\n\n\n".split("\\p{javaWhitespace}+").length);
        System.out.println("10\n".split("\\p{javaWhitespace}+").length);
        System.out.println("hello\n".split("\\p{javaWhitespace}+").length);
    }
}

Output:

true
0
1
1

This is applicable to all nextXXX() except nextLine() whose documentation (excerpt given below) is quite clear how it behaves different from other nextXXX().

Advances this scanner past the current line and returns the input that was skipped. This method returns the rest of the current line, excluding any line separator at the end. The position is set to the beginning of the next line. Since this method continues to search through the input looking for a line separator, it may buffer all of the input searching for the line to skip if no line separators are present.

In other words, nextLine() will catch everything including the whitespace character entered directly or leftover from the previous input.

Arvind Kumar Avinash
  • 50,121
  • 5
  • 26
  • 72