--- title: "how it works: java scanner" tags: programming, tutorial --- # 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 :cry: 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 :slightly_smiling_face: ## setting it up setting up a scanner is pretty simple ```java Scanner keyboard = new Scanner(System.in); ``` after this, you can ask the user a question like so ```java 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()` ```java System.out.print("Enter your age: "); int age = keyboard.nextInt(); System.out.print("Enter your name: "); String name = keyboard.nextLine(); ``` ![](https://i.imgur.com/M58EoPZ.gif) 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 ```java 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: ```java 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 ```java 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 ```java 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 ```java 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 :slightly_smiling_face: