Scanner splits a character source into tokens and converts those tokens to values; line-oriented input needs a separate rule for consuming line endings.
Java console input: Scanner tokens, lines and validation
Java 8+. The program uses only JDK classes and runs without a framework.
Decide what one record means
A depot intake screen asks for a parcel count followed by a destination line. The count is a token. The destination can contain spaces. Reading both with next() silently changes the second field into its first word; reading nextInt() followed immediately by nextLine() can instead return the rest of the count line.
Own the boundary. This program parses one complete count line using Integer.parseInt, then reads the complete destination line. It rejects counts outside the accepted range before creating any shipment records. A malformed number and an exhausted input are different failures, even when the interface eventually displays one validation message.
The fixture is a String so the example never waits for someone to type during a test. Replace it with System.in for a console application. Do not close a wrapper around System.in if another part of the process still owns that stream. The fixture scanner has an independent source and can be closed safely.
Tokens are state, not just values
hasNextInt() checks the next token without consuming it. If validation fails, an input loop must consume or reject that token before trying again; otherwise it repeats forever at the same position. Locale also affects numeric parsing. A machine protocol should declare its number format rather than inherit the operator’s workstation settings.
Keep parsing separate from business validation. The string "-4" is a valid integer representation but an invalid parcel count for this application. That distinction makes tests smaller: parsing checks syntax and range, while the receiving method checks what counts are allowed. Read exception boundaries before replacing every error with a default zero.
Working program
import java.util.Scanner;
public class DepotIntake {
static int parcelCount(String line) {
int count = Integer.parseInt(line.trim());
if (count < 1 || count > 500) {
throw new IllegalArgumentException("Parcel count outside 1..500");
}
return count;
}
public static void main(String[] args) {
try (Scanner input = new Scanner("6\nPune Central Depot\n")) {
int count = parcelCount(input.nextLine());
String destination = input.nextLine().trim();
if (destination.isEmpty()) throw new IllegalArgumentException("Destination required");
System.out.println(count + " parcels -> " + destination);
}
try {
parcelCount("-4");
} catch (IllegalArgumentException rejected) {
System.out.println("Rejected count");
}
}
}Output
6 parcels -> Pune Central Depot
Rejected countCost and failure boundaries
Parsing scans the submitted count line; reading a destination scans that line too. For L input characters, budget O(L) work and storage for the strings and scanner state. Scanner performs pattern-based token processing, so a buffered reader and explicit parser may suit high-volume import work better. Measure the import, not a single interactive keystroke.
Integer.parseInt rejects values outside int range. A valid long value does not fit automatically. Limiting the line length before parsing also prevents an accidental multi-megabyte field from becoming routine input. Test blank lines, whitespace-only destinations, missing lines, malformed digits and the two count boundaries.
Common Mistakes
- Do not mix token and line reads without consuming the remainder intentionally.
- Do not retry the same rejected token forever.
- Do not close a shared input stream you do not own.
Connect the contracts
Compare the boundary explained in Primitive ranges with the assumptions made by this program.
Compare the boundary explained in Buffered file input with the assumptions made by this program.
