Try   HackMD

the nextLine scanner problem

you're trying to write a program that asks the user to type a number using nextInt(). then you ask them to type some text with nextLine(), but it just fails! it doesn't even give you an error message; it completely skips your nextLine() function

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

this is the most common issue to run into when starting out with scanners. even if you've been lucky not to run into it, understanding why it happens gets at the core of understanding scanners. so let's figure it out

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

setting it up

setting up a scanner is pretty simple

Scanner keyboard = new Scanner(System.in);

after this, you can ask the user a question like so

System.out.print("Enter your name: ");
String name = keyboard.nextLine();

the problem

but something weird happens when you try to use nextInt(), nextFloat(), or any of the other next___() scanner functions followed by nextLine()

System.out.print("Enter your age: ");
int age = keyboard.nextInt();
System.out.print("Enter your name: ");
String name = keyboard.nextLine();

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

it's as if java just skips right over the keyboard.nextLine() function and sets the name variable to an empty string! and that's almost exactly what's happening behind the scenes

the scanner buffer

whenever you use one of a scanner's next___() functions, two things happen:

  1. it stores everything you typed into a buffer
  2. it'll look for the next int, float, word, etc based on which function you used

but what's important to know is that, after it finds and returns a match, it doesn't delete the rest of its buffer! that means if you use nextInt() and the user types 23 apples, the 23 will be returned and the string " apples" will be sitting in the buffer waiting for the next function you use.

newlines

the other important thing to know is how scanners handle newlines. this is a special character that represents breaks between lines of text. it's how you separate paragraphs. in the coding world, it's represented as a \n. if i have a document that reads

hello
world

this would be represented in code as "hello\nworld". and one of these newline characters gets sent to the scanner buffer each time you hit enter. looking for that \n is how the nextLine() function knows that it's found the end of a line

the cursor

you can think of the buffer this way: the scanner has a cursor (like your cursor when editing a document) that it moves through the buffer to keep track of where it's at.

going back to our 23 apples example, our buffer looks like this after the user hits enter: 23 apples\n. when you call nextInt(), picture the scanner moving a cursor through the buffer like so:

|23 apples\n
2|3 apples\n
23| apples\n

bam, right there it says "whoops, no more numbers" and stops. it returns the 23 and leaves apples\n in the buffer. then when you call nextLine() it does the same thing, except instead of stopping at a space it'll stop at the \n

drop the newline

the last thing to understand, before explaining the mechanism behind our problem and how to solve it, is that nextLine() does something slightly different from all of the other next___() functions. in the last example, we saw how nextInt() stops the cursor before it reaches the space, leaving apples (with a space) in the buffer. it keeps moving the cursor until there are no more numbers and then stops. nextLine() keeps moving the cursor until it finds a \n character and then moves the cursor just past it.

that is, if we have hello\nworld in the buffer, calling nextLine() will move the cursor:

|hello\nworld
h|ello\nworld
he|llo\nworld
hel|lo\nworld
hell|o\nworld
hello|\nworld
hello\n|world

but wait, does that mean that if we run String word = keyboard.nextLine() that word will be set to "hello\n"? nope! nextLine() takes care of that by dropping the \n character from its output. that's what makes it different from other scanner functions and why it'll be the solution to our issue.

putting it together

so let's write a program that asks the user for their age, name, and favorite color

System.out.print("Age: ");
int age = keyboard.nextInt();
System.out.print("Name: ");
String name = keyboard.nextLine();
System.out.print("Favorite color: ");
String color = keyboard.nextLine();

the user might type something like this

23
jack
purple

or in code format: 23\njack\npurple\n. so let's look at what happens at each next___() function (with a | to represent where the cursor is after the function finishes):

function cursor returns
nextInt() 23|\njack\npurple\n 23
nextLine() 23\n|jack\npurple\n ""
nextLine() 23\njack\n|purple\n "jack"

see what happened there? the first time we call nextLine() trying to get the user's name, the buffer in front of the cursor looks like \njack\npurple\n. so nextLine() does what it usually does and stops as soon as it finds the first \n (which is there from when the user typed 23 and hit enter). it stopped before we ever even got to the name! which means the second time we called nextLine(), trying to get the user's favorite color, the cursor was way further back than we expected, and we got the user's name instead.

to re-iterate:

  1. the user typed 23\n
  2. nextInt() grabbed the number 23 but left the \n in the buffer
  3. so when we called nextLine(), it just stopped at the \n leftover from the 23, rather than getting the name that the user typed after it

the solution

you might already know this or have been able to infer it from everything we've discussed, but the solution is pretty simple: any time we expect the user to hit enter after a number, we need to call nextLine() after calling nextInt(). when the user types a number and hits enter, it leaves a \n in our buffer that nextInt() doesn't remove, so we need to call nextLine() to remove it. this same idea applies to nextFloat(), nextChar(), etc. for our example, this looks like:

System.out.print("Age: ");
int age = keyboard.nextInt();
// move past the extra newline from hitting enter
keyboard.nextLine();
System.out.print("Name: ");
String name = keyboard.nextLine();
System.out.print("Favorite color: ");
String color = keyboard.nextLine();

and there we go! we don't even need to store the output in a variable; we just call nextLine() to move the cursor and move on.

when to use it

after learning this, some people are tempted to always put an extra nextLine() after any nextInt(), nextFloat(), etc, but we only want to use it specifically when we expect the user to hit the enter key after an integer.

for example, suppose we want to ask the user for their 2 favorite numbers and then their name

System.out.println("What are you 2 favorite numbers?");
int num1 = keyboard.nextInt();
int num2 = keyboard.nextInt();
// move past the extra newline from hitting enter
keyboard.nextLine();
System.out.println("What is your name?");
String name = keyboard.nextLine();

we don't want to call nextLine() after every time we use nextInt(). we only want to use it when we know the user hit the enter key after a specific int (num2 in our example)

23 apples and a space

you might have noticed in the 23 apples example that, after calling nextInt(), we're left with apples\n in the buffer-with a space in the beginning. so if we then use nextLine(), the output will be " apples"! we figured out how to move the cursor past a newline, but it's not a newline we want to skip past this time, and there's no nextSpace() function to move our cursor past that space.

instead, we can use skip(). we can pass a string to skip, and it'll move the cursor past that text in the buffer.

so our new code could become

System.out.println("Enter a quantity and type of items:");
int quantity = keyboard.nextInt();
keyboard.skip(" ");
String itemType = keyboard.nextLine();

if the user types 23 apples\n, then:

  • nextInt() will return 23
  • skip(" ") will move the cursor past the space
  • nextLine() will return just the word "apples" with no space

beware

if you use skip(), but the string you specify isn't the immediately next string in the scanner buffer, it'll just hang indefinitely! it's not like any of the other scanner functions; it won't just look until it finds the thing it's looking for and then stop there.

e.g. if the user had typed 23apples\n without a space, keyboard.nextInt() would have moved the cursor to 23|apples\n and then keyboard.skip(" ") would have just frozen our program because the very next character is an "a" and not a space.

if you're not sure what the user is going to type, then use next() or nextLine() like normal and simply remove the space afterwards

String itemType = keyboard.nextLine(); // " apples"
itemType = itemType.strip(); // "apples"

summary

  • whenever you hit enter, you add that line of text to the scanner buffer with a \n at the end
  • nextLine() moves the buffer cursor past the next \n character it finds and removes that \n from its output
  • next() does the same thing, except it'll look for the next space, tab, or newline
  • nextInt(), nextFloat(), and every other next___() function moves the cursor just after the next int, float, etc it finds and doesn't remove anything from the buffer or its output.

fin

and that's it! hopefully now you have a better grasp on how scanners work

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →