alekscooper
alekscooper

Reputation: 831

Why does Java ask me to hit Enter again?

I've been racking my brain for a while trying to understand how Scanner works. So here's the code:

Scanner sc = new Scanner(System.in);
String s = sc.nextLine();
String p = sc.nextLine();
System.out.println(s);
System.out.println(p);
System.out.println(sc.hasNextLine());

What I expect:

Love is good  <- press ENTER
Love is blind <- press ENTER
Love is good  <- output
Love is blind <- output
false

What I have:

Love is good   <- I press ENTER
Love is blind  <- I press ENTER
Love is good   <- output
Love is blind  <- output
<- press ENTER
true <- output

What I do not understand:

  1. Instead of immediate printing this line - System.out.println(sc.hasNextLine()); - it makes me to press ENTER again
  2. It prints true instead of false while there no more lines or symbols

What I have read: I have read a dozen of stackoverflow answers about using hasNextLine() after nextInt() and about how nextInt() does not consume the final symbol in the line but I don't understand why, even though I don't use nextInt() in here, I still need to press ENTER one more time and why hasNextLine() is true.

Upvotes: 14

Views: 4961

Answers (6)

Bernhard Colby
Bernhard Colby

Reputation: 319

In your case, I debugged your example and saw that

System.out.println(sc.hasNextLine());

line waits for a new input. It is neither true nor false. It does not exist. That is why, it blocks the application. It does not matter what you entered (enter or any other button on the keyboard), it would give you true because you supplied a new input.

Upvotes: 0

Sнаđошƒаӽ
Sнаđошƒаӽ

Reputation: 17562

Instead of Scanner use BufferedReader like so:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

class Test {
    public static void main(String[] args) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

        String s = reader.readLine();
        String p = reader.readLine();
        System.out.println(s);
        System.out.println(p);      
        System.out.println(reader.ready());
    }
}

For more reading into the matter, look here and here. As a rule of thumb, when you need parsing stuff (like nextInt) use Scanner, otherwise stick to BufferedReader. BufferedReader is a lot faster than Scanner too.

As for why you got that troublesome behavior, see the javadoc for Scanner.

The part that applies in your particular case is:

A scanning operation may block waiting for input.

What this means in your case is: after the first two lines are read by Scanner, the Scanner was waiting for input, caused by its method call sc.hasNextLine(). Then when Enter was hit, it got an input (hence it prints true, according to docs it returns true when there is input). As after the method call sc.hasNextLine() there are no more executable lines in your program, the program ends, giving the illusion that it required two enter hits.

Upvotes: 14

J. Su.
J. Su.

Reputation: 451

You have the problem, that the Scanner is reading from the given InputStream which can be something like a file or in your case System.in.

As described in this answer a File has an end and the sc.hasNextLine() will return false. By using the stream you expect it not to have an end to be able to provide input data and therefore will block and wait for your next input.

Maybe you can think of some "exiting char" (here it is the '#'):

Scanner sc = new Scanner(System.in);
StringBuilder builder = new StringBuilder();
while (sc.hasNextLine()) {
    String line = sc.nextLine();
    if (line.equals("#")) {
        break;
    }
    builder.append(line + "\n");
}
System.out.println(builder.toString());
sc.close();

Upvotes: 6

Has QUIT--Anony-Mousse
Has QUIT--Anony-Mousse

Reputation: 77454

You are asking for three lines of input!

Standard input always has one more line coming until you close the terminal. On a Unix system, you can probably press Ctrl+D at the end, and it will return flase (= input closed).

The program would behave as expected if you had a finite input. But interactive input: how does the program know the user does not intend to input Shakespeare next?

The function hasNextLine() will wait for new input to arrive (or for the signal that there cannot be new input). This function is not for "did the user already input another line" but instead means "wait for the next line". So for practical purposes, hasNextLine() is equivalent to "is the user input still connected, and could it eventually contain another line".

Why do you need that last line? Just remove it!

Upvotes: 9

Rohan Gill
Rohan Gill

Reputation: 101

First of all you are using Scanner declared to System.in so this means you are asking .in to check if their is any more value so it waits for the user to input something and after you press enter it is obvious that it returns true.

So if you want to check s or p declare Scanner like this:

Scanner sc = new Scanner(s);

or

Scanner sc = new Scanner(p);

then check for sc.hasNextLine(); this should return false as much I know but for user input I would recommend to create another Scanner variable and then take values from the user and use sc for your hasNextline() thing.

I hope the very first logic helps you.

Upvotes: 10

Arc676
Arc676

Reputation: 4465

From the Scanner documentation (emphasis by me):

public boolean hasNextLine()

Returns true if there is another line in the input of this scanner. This method may block while waiting for input. The scanner does not advance past any input.

What's probably happening is that hasNextLine is blocking because it's waiting for input, which you give by pressing enter.

Upvotes: 11

Related Questions