Java Scanner Class Explained — Read Input Like a Pro (With Real Examples)
Every useful program in the real world needs to talk to a human. A login screen needs a username. A calculator needs two numbers. A quiz app needs an answer. Without the ability to read what a user types, your Java program is essentially a locked room — it can think, but it can't listen. That's where the Scanner class steps in, and it's one of the very first things every Java developer learns for exactly that reason.
Before Scanner existed, reading input from a keyboard in Java was genuinely painful. You had to work with low-level streams, wrap them in readers, and handle checked exceptions just to read a single number. Scanner wraps all of that complexity in a clean, beginner-friendly API. You get methods like nextLine(), nextInt(), and nextDouble() that read exactly the type of data you want — no ceremony required.
By the end of this article you'll know how to set up a Scanner, read strings and numbers from the keyboard, read input from a file, close the Scanner correctly, and — critically — avoid the two nasty bugs that trip up almost every beginner. You'll also have three fully runnable programs you can copy, run, and tweak right now.
What Is Scanner and How Do You Set It Up?
Scanner lives in the java.util package, which means you need to import it before you can use it. Think of an import like telling your kitchen which cookbook to pull off the shelf — you're telling Java 'I need the Scanner recipe from the java.util cookbook'.
Once imported, you create a Scanner object. An object is just a working instance of a class — like printing a specific form from a template. You hand the Scanner constructor a source to read from. The most common source is System.in, which represents the keyboard. Literally: System.in means 'standard input', which is the stream of characters that flows in when a user types.
The Scanner then sits and waits. When your code calls a method like nextLine(), the program pauses, a cursor blinks in the terminal, the user types something and hits Enter, and Scanner captures everything typed before that Enter key.
One important habit to build immediately: always close your Scanner when you're done with it. A Scanner holds a connection to its source (keyboard or file). Leaving it open is like leaving a tap running — it wastes resources and can cause subtle bugs in larger programs.
import java.util.Scanner; // Step 1: import Scanner from the java.util package public class GreetUser { public static void main(String[] args) { // Step 2: create a Scanner object connected to the keyboard (System.in) Scanner keyboardReader = new Scanner(System.in); // Step 3: prompt the user so they know what to type System.out.print("Enter your name: "); // Step 4: read the entire line the user types (including spaces) String userName = keyboardReader.nextLine(); // Step 5: use the input — here we just greet the user System.out.println("Hello, " + userName + "! Welcome to TheCodeForge."); // Step 6: always close the Scanner when you're finished reading keyboardReader.close(); } }
Hello, Sarah! Welcome to TheCodeForge.
Reading Different Data Types — Strings, Integers and Decimals
Scanner doesn't just read raw text. It can parse that text directly into the Java data type you need — int, double, boolean, and more. Each data type has its own dedicated method, and choosing the right one saves you from having to convert strings manually.
nextLine() reads an entire line of text up to (but not including) the newline character created by pressing Enter. It returns a String.
next() reads a single 'token' — one word, stopping at whitespace. Useful for reading one word at a time.
nextInt() reads the next token and tries to parse it as a whole number (int). If the user types '42', you get the integer 42, ready for arithmetic.
nextDouble() does the same for decimal numbers. The user types '3.14' and you get a double you can multiply, divide, or compare.
The program below builds a simple age-and-height form. Notice how we mix data types in one conversation — that's exactly what real programs do.
import java.util.Scanner; public class UserProfileForm { public static void main(String[] args) { Scanner inputReader = new Scanner(System.in); // --- Read a String --- System.out.print("What is your full name? "); String fullName = inputReader.nextLine(); // reads the whole line, spaces included // --- Read an integer --- System.out.print("How old are you? "); int age = inputReader.nextInt(); // parses the typed text directly into an int // --- Read a double --- System.out.print("What is your height in metres? "); double heightInMetres = inputReader.nextDouble(); // parses into a decimal number // --- Display a summary --- System.out.println("\n--- Profile Summary ---"); System.out.println("Name : " + fullName); System.out.println("Age : " + age + " years"); System.out.printf("Height : %.2f m%n", heightInMetres); // %.2f = 2 decimal places // Calculate something real with the input if (age >= 18) { System.out.println("Status : Adult"); } else { System.out.println("Status : Minor"); } inputReader.close(); } }
How old are you? 24
What is your height in metres? 1.68
--- Profile Summary ---
Name : Maria Gonzalez
Age : 24 years
Height : 1.68 m
Status : Adult
Reading Input From a File — Same Tool, Different Source
Here's something that surprises many beginners: Scanner isn't just for keyboards. Because it accepts any source that Java can read from, you can point it at a text file and it reads line by line (or token by token) in exactly the same way. This is genuinely powerful — learn Scanner once, use it two ways.
To read from a file, you create a File object pointing at the file path, then pass that File object to the Scanner constructor instead of System.in. The rest of the API — nextLine(), nextInt(), hasNextLine() — works identically.
hasNextLine() is your best friend when reading files. It returns true as long as there are more lines to read, which makes it a perfect condition for a while loop. Without it you'd have to know in advance how many lines the file has.
Note that opening a file can fail (file not found, permission denied), so Java forces you to handle a FileNotFoundException. We use a try-with-resources block below, which is the modern, correct approach — it automatically closes the Scanner when the block ends, even if an exception occurs.
import java.util.Scanner; import java.io.File; // needed to represent the file on disk import java.io.FileNotFoundException; // thrown if the file doesn't exist public class FileLineReader { public static void main(String[] args) { // Imagine scores.txt contains: // Alice 95 // Bob 87 // Carol 92 File scoresFile = new File("scores.txt"); // point to the file // try-with-resources: Scanner is automatically closed when the block ends try (Scanner fileScanner = new Scanner(scoresFile)) { int lineNumber = 1; // hasNextLine() returns true if there is another line to read while (fileScanner.hasNextLine()) { String currentLine = fileScanner.nextLine(); // read one full line System.out.println("Line " + lineNumber + ": " + currentLine); lineNumber++; } System.out.println("\nFinished reading " + (lineNumber - 1) + " lines."); } catch (FileNotFoundException exception) { // This runs if scores.txt doesn't exist in the project directory System.out.println("Error: File not found — " + exception.getMessage()); } } }
Line 2: Bob 87
Line 3: Carol 92
Finished reading 3 lines.
Validating Input in a Loop — Building a Bulletproof Input Reader
Real programs can't trust users to type perfectly. Someone will type 'abc' when you asked for a number. If nextInt() gets a non-numeric token it throws an InputMismatchException and crashes your program. That's a terrible user experience.
The professional solution is to validate input inside a loop. Scanner's hasNextInt() method (and its siblings hasNextDouble(), hasNextLong()) lets you check whether the next token is actually parseable as that type — before you try to parse it. Think of it as asking 'is the next thing in the queue actually a number?' before reaching in to grab it.
The loop below keeps asking until the user provides a valid positive integer. Notice two things: we call next() to consume the bad token when validation fails (otherwise Scanner is stuck on the same bad input forever), and we give the user a clear error message so they understand what went wrong.
import java.util.Scanner; public class SafeAgeInput { public static void main(String[] args) { Scanner console = new Scanner(System.in); int userAge = -1; // sentinel value: -1 means 'not yet set' // Keep looping until we have a valid age while (userAge < 0 || userAge > 130) { System.out.print("Please enter your age (0–130): "); if (console.hasNextInt()) { // check BEFORE parsing — safe! userAge = console.nextInt(); if (userAge < 0 || userAge > 130) { // The input was an integer but outside our acceptable range System.out.println("That age isn't realistic. Try again."); } } else { // The input wasn't an integer at all (e.g., the user typed 'hello') String badInput = console.next(); // MUST consume the bad token or we loop forever System.out.println("'" + badInput + "' is not a number. Please type digits only."); } } System.out.println("Great — you are " + userAge + " years old."); console.close(); } }
'hello' is not a number. Please type digits only.
Please enter your age (0–130): -5
That age isn't realistic. Try again.
Please enter your age (0–130): 27
Great — you are 27 years old.
| Scanner Method | What It Reads | Returns | Stops At |
|---|---|---|---|
| nextLine() | Everything up to Enter key | String (can contain spaces) | Newline character \n |
| next() | One word / token | String (no spaces) | Any whitespace |
| nextInt() | Next token as a whole number | int | Whitespace (leaves \n behind) |
| nextDouble() | Next token as a decimal | double | Whitespace (leaves \n behind) |
| nextBoolean() | Next token as true/false | boolean | Whitespace |
| hasNextLine() | Does another line exist? | boolean (true/false) | Does not consume input |
| hasNextInt() | Is the next token an int? | boolean (true/false) | Does not consume input |
🎯 Key Takeaways
- Scanner is a wrapper around any readable source — swap System.in for a File object and the entire API works identically, which means one skill covers two common use cases.
- nextInt(), nextDouble() and friends leave the newline character in the buffer — always consume it with an extra nextLine() before reading your next string to avoid the empty-string bug.
- Always use hasNextInt() (or hasNextDouble()) to validate input before parsing it — nextInt() on bad input throws InputMismatchException and crashes; hasNextInt() peeks safely without consuming the token.
- Create exactly one Scanner per input source and close it exactly once — multiple Scanners on System.in will cause NoSuchElementException; use try-with-resources for file Scanners to guarantee cleanup even if an exception occurs.
⚠ Common Mistakes to Avoid
- ✕Mistake 1: Calling nextLine() right after nextInt() returns an empty string — When nextInt() reads a number, it leaves the newline character (\n from pressing Enter) sitting in the input buffer. The very next nextLine() call reads that leftover newline and returns an empty string, completely skipping the user's actual next input. Fix: add an extra inputReader.nextLine() call immediately after nextInt() (or nextDouble()) to flush that leftover newline before you read your real string data.
- ✕Mistake 2: Forgetting to consume the bad token inside a hasNextInt() validation loop — If the user types a non-integer and you call next() to reject it but forget to actually call next() to remove it from the buffer, Scanner is stuck reading the same bad token on every loop iteration. The loop spins forever printing the same error. Fix: always call console.next() (assigning it to a variable is optional but good practice) inside the else branch to discard the invalid input before looping back.
- ✕Mistake 3: Creating multiple Scanner objects pointing to System.in — Beginners sometimes create a new Scanner(System.in) in multiple methods or classes. Closing one of them also closes System.in itself, making all other Scanners unusable and throwing a NoSuchElementException. Fix: create one Scanner object, pass it around as a method parameter or store it in a shared location, and close it exactly once when the entire program is done reading input.
Interview Questions on This Topic
- QWhat is the difference between next() and nextLine() in Java's Scanner class, and when would you choose one over the other?
- QWhy does calling nextLine() immediately after nextInt() sometimes return an empty string, and how do you fix it?
- QIf you need to read from both the keyboard and a file in the same program, how would you structure your Scanner usage to avoid resource leaks?
Frequently Asked Questions
Do I need to close the Scanner after using it?
Yes, you should always close a Scanner when you're finished with it. An unclosed Scanner holds an open connection to its source (keyboard or file), which wastes system resources. For file Scanners, use try-with-resources to close automatically. For System.in, call close() at the end of your program — but be aware that closing it also closes System.in itself, so only do it once.
What is the difference between Scanner and BufferedReader in Java?
Scanner is easier to use for beginners because it parses data types directly (nextInt(), nextDouble(), etc.) and works with multiple sources including keyboards and files. BufferedReader is faster and better for reading large files line by line, but it only returns Strings — you have to parse types manually. For most beginner and intermediate programs, Scanner is the right choice. Switch to BufferedReader when performance with large files becomes a concern.
Why does my Scanner program skip a line of input without waiting for me to type?
This is almost certainly the nextInt()-then-nextLine() bug. When you read a number with nextInt(), it consumes the digits but leaves the Enter key's newline character in the input buffer. The immediately following nextLine() reads that leftover newline and returns instantly with an empty string. Fix it by adding an extra scanner.nextLine() call right after nextInt() to discard the leftover newline before you read your actual string.
Written and reviewed by senior developers with real-world experience across enterprise, startup and open-source projects. Every article on TheCodeForge is written to be clear, accurate and genuinely useful — not just SEO filler.