Scanner is a thing that will take any stream of textual input (characters) and chop it into distinct pieces.
It knows how to lop things into pieces by looking for the so-called delimiter pattern. All the things in between any 2 delimiter patterns are called tokens. The delimiter bits are tossed away, and only the tokens are returned. Thus, a scanner breaks down any input into a sequence of token - delimiter - token - delimeter - token - delimiter - and so on, tossing away the delimiters, and giving you the tokens. Optionally, by calling e.g. .nextInt()
, you're asking it to also interpret the token in a specific way. But the token/delimiter/token flow is just how it works; .nextInt()
will not magically work out if you enter '123hello' - that will crash, because '123hello' will be the token first, and the Int
part only kicks in after that, and asks to treat that token as an int, which won't work, as it isn't an int. nextInt
is just convenience for Integer.parseInt(next())
, that is all.
So, all you really want is to read that newline, or rather blank input, as a token.
But, by default, that is impossible: The delimiter pattern for a newly created scanner (so, including the one you made here) is "\\s+"
. This is a regular expression that means: "1 or more characters, all of which count as whitespace as per the unicode specification". Enter is whitespace. So is tab, space, and a bevy of more exotic characters like the non-breaking space.
A single newline, and multiple newlines, are all just a single delimiter to a scanner. It is therefore impossible to do what you want with a default-configured scanner - all characters that are part of the delimiter are tossed, so you need the input to move from 'part of a delimiter' to 'part of a token' and back again in order to see anything with your .next()
calls.
There are 2 solutions to this. The commonly advised but stupid solution, and the less commonly advised, correct solution.
The right way: "\\s+"
is a bad default. What you usually want is for the delimiter to be a single newline, and not 'any amount of whitespace'. This way, to read entire names (with spaces in them), just call .next()
. Each and every enter press separates 1 token. Now, if you press enter more than once, you just get a bunch of blank-string tokens back, which you can read with e.g. next(). It will return a blank string. To do that, immediately after invoking
new Scanner, invoke:
scanner.useDelimiter("\r?\n")`. This pattern represents a newline on either windows or unix.
The bad way (I explain it here because you're going to hear this advice, so I best explain why it is bad advice, given that it is so common!): Use nextLine()
. This foregoes the delimiter/token concept entirely, but it does not work well with any other method in scanner. For example, if you invoke nextInt()
to read an integer and then nextLine()
to read somebody's full name, it doesn't work, because nextLine()
will actually return all characters starting at the first character of the delimiter (e.g. after the last character of the previous token) that caused the last next()
method to return, all the way to the newline. So, assuming the user hits their age, hits enter, and types their name, That nextLine()
call returns nothing: It returns the characters between the end of that integer, and the next newline, which is blank. That's why it is a bad idea that is fragile and weird. Don't do this.
All you then have to do to fix your code, is realize that after String input = read.next()
, input
will be blank; e.g. input.isEmpty()
will be true, input.length()
will return 0, and input.equals("")
will be true. You can then exit the while
construct, e.g. with a break
statement. Or straight up System.exit(0);
- whichever you feel is best.