Reading input with Scanner
Exceptions, collections and modern Java11 min readLesson 3 of 6
3.1 Reading tokens
Scanner reads text and converts tokens to values. Create it with a source: new Scanner(System.in) for the keyboard, a String for testing, or a Path for a file. The class is in java.util, so it needs an import.
next() returns the next token as a String. nextInt(), nextDouble(), and nextBoolean() parse the next token as that type. Tokens are separated by whitespace by default.
hasNext() reports whether another token exists. hasNextInt() checks the next token before parsing, which avoids an exception on bad input. Use the check when the source may contain unexpected text.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner("Asha 16 92");
String name = scanner.next();
int age = scanner.nextInt();
int score = scanner.nextInt();
System.out.println(name + " " + age + " " + score);
scanner.close();
}
}Output
Asha 16 92
3.1.1 The nextLine trap
nextInt() reads a token and leaves the rest of the line, including the line break, in the buffer. A following nextLine() returns the remaining part of that line, often an empty string. The name that was supposed to be read next stays in the buffer.
Read the leftover line after nextInt() when the next value is a full line. Another option is to read every value with nextLine() and parse it with Integer.parseInt. Choose one style and keep it through the input section.
This behavior follows from token reading. A token ends before the whitespace, so the whitespace is not consumed as part of the number.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner("""
16
Asha
""");
int age = scanner.nextInt();
String leftover = scanner.nextLine();
String name = scanner.nextLine();
System.out.println("Age " + age);
System.out.println("Leftover length " + leftover.length());
System.out.println("Name " + name);
}
}Output
Age 16 Leftover length 0 Name Asha
3.1.2 Validating input
hasNextInt() returns true only when the next token can be parsed as an integer. A loop can skip or report bad tokens without crashing. InputMismatchException is thrown when a parse method is called on text that does not match.
A validation loop asks again while the value is outside a range. With System.in, the loop needs a prompt, but the structure is the same: read, check, repeat.
A message should say what is accepted. Printing the expected range and type helps the person at the keyboard more than printing an exception class.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner("12 x 7 30");
int total = 0;
while (scanner.hasNext()) {
if (scanner.hasNextInt()) {
total += scanner.nextInt();
} else {
System.out.println("Skipped: " + scanner.next());
}
}
System.out.println("Total: " + total);
}
}Output
Skipped: x Total: 49
3.1.3 Files and closing
A Scanner can read a file: new Scanner(Path.of("data.txt")). The constructor throws IOException, a checked exception, so the method must declare it or use try-with-resources.
Close a Scanner when it reads a file or a string. A Scanner on System.in wraps a shared stream. Closing it also closes the stream for the rest of the program, so many programs leave it open.
Try-with-resources is the clean way to close a file scanner. The reader closes at the end of the block, even if parsing fails.
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
Path file = Path.of("scores.txt");
Files.writeString(file, "80 90 70");
try (Scanner scanner = new Scanner(file)) {
int total = 0;
while (scanner.hasNextInt()) {
total += scanner.nextInt();
}
System.out.println(total);
}
}
}Output
240
3.1.4 Splitting and parsing
Scanner reads tokens; String.split cuts a line on a delimiter. Both have a place. Use split when a line has a known format such as comma-separated values. Use Scanner when values are separated by whitespace and mixed types matter.
Integer.parseInt converts a trimmed string to an int. Double.parseDouble does the same for decimals. Wrap the parse in a try/catch only when the text may be invalid and the program can recover.
Keep the input rules in one method when several prompts share them. That method returns a value that has passed the checks, so the rest of the program can use it without repeating validation.
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner("Ravi 78");
String name = scanner.next();
int score = scanner.nextInt();
String band = score >= 75 ? "distinction" : "pass";
System.out.println(name + ": " + band);
scanner.close();
}
}Output
Ravi: distinction
3.1.5 Practice
- Read a name and two integers from a string with
Scannerand print their sum. - Reproduce the
nextIntandnextLinebehavior with16followed byAshaon the next line. - Loop over
"12 x 7 30"and skip non-integers, printing the total. - Write a file with three numbers, read it with
Scanner, and print the sum. - Read a name and score, then print the score band.
For step 2, print the length of the leftover line. A length of 0 shows that the line break was consumed by the next call.
