TL;DR
nextLine()
is safe to call when (a) it is first reading instruction, (b) previous reading instruction was also nextLine()
.
If you are not sure that either of above is true you can use scanner.skip("\\R?")
before calling scanner.nextLine()
since calls like next()
nextInt()
will leave potential line separator - created by return key which will affect result of nextLine()
. The .skip("\\R?")
will let us consume this unnecessary line separator.
skip
uses regex where
\R
represents line separators
?
will make \R
optional - which will prevent skip
method from:
- waiting for matching sequence
- in case of reaching end of still opened source of data like
System.in
, input stream from socket, etc.
- throwing
java.util.NoSuchElementException
in case of
- terminated/closed source of data,
- or when existing data doesn't match what we want to skip
Things you need to know:
text which represents few lines also contains non-printable characters between lines (we call them line separators) like
carriage return (CR - in String literals represented as "\r"
)
line feed (LF - in String literals represented as "\n"
)
when you are reading data from the console, it allows the user to type his response and when he is done he needs to somehow confirm that fact. To do so, the user is required to press "enter"/"return" key on the keyboard.
What is important is that this key beside ensuring placing user data to standard input (represented by System.in
which is read by Scanner
) also sends OS dependant line separators (like for Windows \r\n
) after it.
So when you are asking the user for value like age
, and user types 42 and presses enter, standard input will contain "42\r\n"
.
Problem
Scanner#nextInt
(and other Scanner#nextType
methods) doesn't allow Scanner to consume these line separators. It will read them from System.in
(how else Scanner would know that there are no more digits from the user which represent age
value than facing whitespace?) which will remove them from standard input, but it will also cache those line separators internally. What we need to remember, is that all of the Scanner methods are always scanning starting from the cached text.
Now Scanner#nextLine()
simply collects and returns all characters until it finds line separators (or end of stream). But since line separators after reading the number from the console are found immediately in Scanner's cache, it returns empty String, meaning that Scanner was not able to find any character before those line separators (or end of stream).
BTW nextLine
also consumes those line separators.
Solution
So when you want to ask for number and then for entire line while avoiding that empty string as result of nextLine
, either
- consume line separator left by
nextInt
from Scanners cache by
- calling
nextLine
,
- or IMO more readable way would be by calling
skip("\\R")
or skip("\r\n|\r|\n")
to let Scanner skip part matched by line separator (more info about \R
: https://stackoverflow.com/a/31060125)
- don't use
nextInt
(nor next
, or any nextTYPE
methods) at all. Instead read entire data line-by-line using nextLine
and parse numbers from each line (assuming one line contains only one number) to proper type like int
via Integer.parseInt
.
BTW: Scanner#nextType
methods can skip delimiters (by default all whitespaces like tabs, line separators) including those cached by scanner, until they will find next non-delimiter value (token). Thanks to that for input like "42\r\n\r\n321\r\n\r\n\r\nfoobar"
code
int num1 = sc.nextInt();
int num2 = sc.nextInt();
String name = sc.next();
will be able to properly assign num1=42
num2=321
name=foobar
.