Java Scanner reads text and can interpret it as tokens such as words, integers or decimal numbers. A Scanner connected to System.in reads console input. A Scanner connected to a string makes a small, repeatable example, which is useful for understanding input behavior before typing values interactively.
The most common beginner surprise is mixing token methods such as nextInt with nextLine. They consume different boundaries. Learn what remains in the input after each call rather than adding an unexplained extra nextLine whenever the output looks wrong.
Construct a Scanner for the input source
Import java.util.Scanner or use its fully qualified name. For interactive input, construct new Scanner(System.in). For these examples, construct a Scanner from a string containing the same characters a user might supply. The methods behave according to the supplied text, while a fixed source makes expected output reproducible.
Scanner can also read other sources, but ownership matters. Closing a Scanner closes its underlying closeable source. In a small program that finishes after input, closing the System.in scanner at the end may be reasonable. In a larger program, closing it inside a helper can prevent later code from reading standard input. Decide which part of the application owns the source rather than creating and closing competing scanners without a plan.
Tokens and lines are different units
By default, Scanner separates tokens using whitespace. next reads the next token, and nextInt interprets a token as an integer. Leading whitespace is skipped for token methods. A full name such as Lina Perez contains two default tokens, so next alone reads only Lina.
nextLine reads the rest of the current line, excluding its line separator. It can return an empty string when the scanner is positioned immediately before a line ending. This is not an input failure: an empty remainder is a valid line result. Choose a token method when separate fields are intended, and a line method when spaces belong to the value. You can change the delimiter, but doing so changes token boundaries and should be part of the stated input format.
Why nextLine seems to skip an answer
After nextInt reads a number, a line separator following that token can remain pending. A subsequent nextLine reads the remainder of that same line, which may be empty. The following user’s line has not necessarily been lost; your calls asked for different pieces of the stream.
One strategy is to consume the rest of the numeric line intentionally before reading the next full line. Another is to read all responses as lines and parse numeric lines with Integer.parseInt. Neither strategy is a universal magic fix. If input places a number and meaningful text on the same line, discarding the remainder would lose that text. Define the input layout first, then choose a sequence of reads that preserves the fields you need.
Validate before interpreting a token
hasNextInt checks whether the next token can be read as an int without consuming it. If it succeeds, nextInt consumes and returns that integer. If it fails, consuming the invalid token with next can allow a validation loop to progress. Repeating hasNextInt forever without consuming or otherwise handling the bad token checks the same input again and again.
Calling nextInt directly on a noninteger token can throw InputMismatchException. Exhausted input can produce NoSuchElementException. A value can also be syntactically numeric but outside the int range. Treat these as different situations when designing feedback. Validation should distinguish an invalid value from no remaining input, especially when a program reads redirected files rather than an interactive terminal.
Locale and interactive prompts
Numeric scanning can depend on the scanner’s locale, including decimal punctuation. Use an explicit locale when a lesson or data format requires predictable parsing. Locale.ROOT is useful for demonstrations using a dot decimal separator. It does not mean every user in every region naturally enters numbers in that format.
For interactive input, print a prompt before reading, often with print so the response can appear on the same line. Do not include user-typed text in the program’s expected output as if Java printed it. In a lesson, show the supplied input separately from generated output. When parsing a whole line, Integer.parseInt requires appropriate valid text; trim surrounding whitespace deliberately if the input contract allows it.
Practice with explained solutions
Task 1. Read a full product name containing spaces after an integer quantity placed on its own line.
Solution. Read the quantity token, consume the remaining numeric line deliberately, then read the next full line. Alternatively, read both lines and parse the quantity line.
Task 2. Explain why hasNextInt alone does not remove a bad token.
Solution. It is a lookahead check. Call next to consume an invalid token, or choose another explicit action, before repeating validation.
Java Summary
- Token reads and line reads consume different boundaries.
- After a token read, nextLine may consume only the current line's empty remainder.
- Lookahead checks do not consume invalid input; an explicit read or exit must make progress.
- Continue with command-line arguments.
Java Examples
Each example shows the code, the output it produces and what each part does.
Read separate numeric tokens
Save this complete program as ScannerNumbers.java. Compile with javac --release 17 ScannerNumbers.java and run with java ScannerNumbers.
public class ScannerNumbers {
public static void main(String[] args) {
try (java.util.Scanner scanner = new java.util.Scanner("4 7")) {
int first = scanner.nextInt();
int second = scanner.nextInt();
System.out.println(first + second);
}
}
}11Line-by-line explanation
- Lines 1 to 9The default whitespace delimiter separates four and seven into two tokens. Each nextInt consumes one token and returns an int. Their sum is eleven. The string source eliminates the need for keyboard input in this worked example. Replacing it with System.in makes the same reads interactive, but the user must then supply the tokens before the program can complete.
Handle the remaining line intentionally
Save this complete program as ScannerLines.java. Compile with javac --release 17 ScannerLines.java and run with java ScannerLines.
public class ScannerLines {
public static void main(String[] args) {
try (java.util.Scanner scanner = new java.util.Scanner("21\nLina Perez\n")) {
int age = scanner.nextInt();
String remainder = scanner.nextLine();
String name = scanner.nextLine();
System.out.println("Remainder length: " + remainder.length());
System.out.println(name + " is " + age);
}
}
}Remainder length: 0
Lina Perez is 21Line-by-line explanation
- Lines 1 to 11nextInt reads twenty-one but leaves the following line boundary. The first nextLine consumes the empty remainder of that numeric line. The next nextLine reads the complete name, including its internal space. Calling next instead for the name would read only Lina. This source deliberately puts age and name on separate lines, so consuming the empty remainder does not discard useful text.
Make progress past invalid input
Save this complete program as ValidatedScanner.java. Compile with javac --release 17 ValidatedScanner.java and run with java ValidatedScanner.
public class ValidatedScanner {
public static void main(String[] args) {
try (java.util.Scanner scanner = new java.util.Scanner("oops 12")) {
if (!scanner.hasNextInt()) {
System.out.println("Rejected: " + scanner.next());
}
if (scanner.hasNextInt()) {
System.out.println("Accepted: " + scanner.nextInt());
}
}
}
}Rejected: oops
Accepted: 12Line-by-line explanation
- Lines 1 to 8The first check recognizes that oops cannot be parsed as int. Calling next consumes that rejected token, moving the scanner forward.
- Lines 9 to 12The second check now sees twelve and reads it successfully. In a repeated validation loop, the same progress requirement applies. This example demonstrates token validation without catching an exception for ordinary invalid input.
Common Java Mistakes
Adding a throwaway nextLine without knowing what it consumes
Do not insert a throwaway nextLine without identifying what it consumes. It can repair a separate-line input sequence but destroy meaningful text when multiple fields share one line. Also avoid a validation loop that only asks hasNextInt repeatedly after a failure. Consume the invalid token, report it or exit according to the contract so the input position changes.
Java FAQ
Why use a string Scanner in examples?
It makes input deterministic and lets you reproduce the exact output. System.in remains the usual source for interactive console programs.
Should every helper close a shared Scanner?
No. The owner of the input resource should manage its lifetime. Closing a shared scanner can close the underlying input needed by later operations.
How do I read input until there is no more?
Loop with while (scanner.hasNextLine()) or while (scanner.hasNextInt()). The loop ends when the input runs out, for example at the end of a piped file. In a terminal, end the input by pressing Ctrl+D on Linux and macOS or Ctrl+Z then Enter on Windows.
How do I read values separated by commas?
Change the delimiter: new Scanner("4,8,15").useDelimiter(",") reads the tokens 4, 8 and 15, which add up to 27. For whole lines of CSV-like input, it's often simpler to read the line and call split(","), then trim and parse each part.
Why does my program seem to freeze at hasNextInt()?
With System.in, hasNextInt() waits until the user types something and presses Enter, because it can't answer without seeing the next token. Print a prompt before calling it so the user knows input is expected.
Java Exercises
Answer each one and check it instantly. If you get stuck, open the hint before the answer.
Why does the first nextLine after reading 21 return an empty string?
Which operation advances past the rejected token oops?
Java Quiz
2 questions to check what you learned.
What does next read by default?
- One whitespace-delimited token
- An entire line including spaces
- Every remaining line
Does hasNextInt consume the token?
- No
- Yes
- Only when invalid