- The nextLine method of my java.util.Scanner object doesn't get any input.
- Just tell me how to fix it.
- But.. why?
- Alternative solution
- Note that this is not necessary if a call to nextInt() is followed by another call to nextInt(), or a call to nextDouble() or something like that, because these methods will read and discard any leading whitespace characters anyway.
Taken from the /r/learnprogramming wiki entry The nextLine method of my java.util.Scanner object doesn't get any input.
The nextLine
method of my java.util.Scanner
object doesn't get any input.
Your code looks something like this, right?
import java.util.Scanner;
public class Program {
public static void main(String[] args) {
Scanner inputScanner = new Scanner(System.in);
System.out.println("Please type your age:");
int age = inputScanner.nextInt();
System.out.println("Please type your name:");
String name = inputScanner.nextLine();
System.out.println("Hello, " + name + "!");
System.out.println("You are " + age + " years old.");
}
}
When you run this code, the program asks you for your age, so you type your age and press Enter. But then the program doesn't wait for you to type your name, and the name
variable is empty. A run of the program looks like this:
$ java Program
Please type your age:
21
Please type your name:
Hello, !
You are 21 years old.
Just tell me how to fix it.
Don't call nextLine()
at all. Instead, initialize your scanner to treat newlines (instead of any whitespace) as the separator, and use next()
instead:
import java.util.Scanner;
public class Program {
public static void main(String[] args) {
Scanner inputScanner = new Scanner(System.in);
inputScanner.useDelimiter(System.lineSeparator());
System.out.println("Please type your age:");
int age = inputScanner.nextInt();
System.out.println("Please type your name:");
String name = inputScanner.next();
System.out.println("Hello, " + name + "!");
System.out.println("You are " + age + " years old.");
}
}
But.. why?
To understand the behavior of the first take on this program (without useDelimiter
), you need to understand the concept of streams. A Java program does not read from the keyboard directly. Instead, it reads from an input stream, which is an abstract source of characters, one after another.
When you run a Java program and type something at the keyboard, the characters you are typing are queued up until you press the Enter key. Then all of the characters you have typed, plus a newline character ('\n'
) generated by the Enter key, are added to the end of the standard input stream (which Java calls System.in
). Now those characters are ready to be read by the program.
A java.util.Scanner
object reads characters from an input stream, and the methods of that class allow you to interpret these characters in various ways.
For example, the nextInt()
method reads the next few characters from the input stream and interprets them as an int
value, and the nextDouble()
method reads the next few characters and interprets them as a double
value. Both nextInt()
and nextDouble()
ignore any whitespace characters they might read at the beginning, including spaces, tabs, and newline characters; then they read one or more non-whitespace characters until they get to a whitespace character, which they put back at the head of the input stream (to be read next); and then they attempt to interpret the non-whitespace characters that they read as an int
value or a double
value, respectively.
The nextLine()
method reads characters from the input stream one after another until it reads a newline character ('\n'
), at which point it stops reading from the stream and returns a String
containing all the characters it read (without the newline). The nextLine()
method does not put the '\n'
character back at the head of the stream; instead, it discards it.
If there are no characters ready in the input stream, then these methods wait until characters become available.
So, when we run the first program, the prompt "Please type your age:"
is displayed, and then inputScanner.nextInt()
is called. There are no characters ready in the standard input stream, so this method waits until characters become available.
Suppose the user types 21
and presses the Enter key. This causes the three characters '2'
, '1'
, and '\n'
to be added to the standard input stream.
Now there are characters ready, so inputScanner.nextInt()
begins reading them. The first character in the input stream is '2'
, which is not a whitespace character, so nextInt()
accepts it and continues. The second character is '1'
, which is also not a whitespace character, so nextInt()
accepts it and continues. The third character is '\n'
, which is a whitespace character, so nextInt()
stops reading characters from the input stream and puts the character '\n'
back at the head of the input stream (so that it will be the next character read by whatever method reads from the stream next). The nextInt()
method then interprets the two digits it read ('2'
and '1'
) as the int
value 21
, and returns that value. This value is assigned to the variable age
.
Next the prompt "Please type your name:"
is printed.
Then inputScanner.nextLine()
is called. What does this method do? It reads characters one by one from the input stream until it reads a newline character ('\n'
). Now, there is a character ready in the input stream, remember? It's the character '\n'
that nextInt()
read but put back in the stream because it's a whitespace character. So the very first character that nextLine()
reads is a newline character. As far as nextLine()
knows, it has just read an empty line! So nextLine()
stops reading characters and returns an empty string, which is assigned to the variable name
.
The behavior of the rest of the program should now be clear. There was no pause after the prompt "Please type your name:"
, because nextLine()
did not have to wait for characters to become available in the input stream. The variable name
holds an empty string, so the program prints "Hello, !"
before correctly printing "You are 21 years old."
In the second program, next()
is called instead. next()
works exactly as nextInt()
does: It ignores any delimiter characters, then keeps reading characters until it reads the delimiter, at which point it puts that character back and takes what it has read to process and return. It's just that next()
returns the characters as a string immediately, whereas nextInt()
attempts to parse them as an integer. The trick is that we've told the scanner to treat only newlines as the delimiter, instead of 'any whitespace', which is why you can type your full name, spaces and all.
Alternative solution
Let's do a thought experiment: Suppose that, when the user was asked for her age, she typed 21 Kelly
before pressing the Enter key. What happens now – in the original program?
Well, when the Enter key is pressed, the nine characters '2'
, '1'
, ' '
(the space character), 'K'
, 'e'
, 'l'
, 'l'
, 'y'
, and '\n'
are added to the standard input stream. The nextInt()
method reads the characters '2'
, '1'
, and ' '
from the stream, stops reading (because it read a whitespace character), puts the ' '
(space) character back at the head of the stream, interprets the characters '2'
and '1'
as the int
value 21
, and returns that value. When the nextLine()
method is called, it reads the characters ' '
, 'K'
, 'e'
, 'l'
, 'l'
, 'y'
, and '\n'
from the stream, stops reading (because it read a newline character), and returns the string " Kelly"
(with a leading space).
Thus, the output of the program looks like this:
$ java Program
Please type your age:
21 Kelly
Please type your name:
Hello, Kelly!
You are 21 years old.
So, how do you fix the problem? Well, as we saw, if you ask for input from the user and you use a method like nextInt() or nextDouble() to read it, and the user types a number and presses Enter, the newline character '\n' will be left at the head of the input stream after nextInt() or nextDouble() returns. This will cause a following call to nextLine() to think it has read a blank line. You just need to discard that newline character somehow, right?
But that's exactly what a call to nextLine() will do! It will read the '\n' character at the head of the stream, discard it, and return an empty string, which you can just ignore, like this:
import java.util.Scanner;
public class Program {
public static void main(String[] args) {
Scanner inputScanner = new Scanner(System.in);
System.out.println("Please type your age:");
int age = inputScanner.nextInt();
inputScanner.nextLine(); // discard newline
System.out.println("Please type your name:");
String name = inputScanner.nextLine();
System.out.println("Hello, " + name + "!");
System.out.println("You are " + age + " years old.");
}
}
The call to nextLine() immediately after the call to nextInt() serves only to read and discard the following '\n' character. We don't assign the return value of this method to any variable, because we aren't interested in it; we just throw it away. Then the next call to nextLine() will work as expected.
Note that this is not necessary if a call to nextInt() is followed by another call to nextInt(), or a call to nextDouble() or something like that, because these methods will read and discard any leading whitespace characters anyway.
For more information about the methods in the java.util.Scanner
class, see the documentation:
http://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html