Java Scanner Class: Reading Files, Strings and Parsing Tokens - Quiz
Total: 5 questions
1. How do you read a text file line by line with Scanner, and why should you specify the charset?
How do you read a text file line by line with Scanner, and why should you specify the charset?
Create a Scanner over a Path with an explicit charset inside try-with-resources and call nextLine() while hasNextLine() returns true. nextLine() returns the line without the line terminator; an empty line of the file comes back as "".
try (Scanner scanner = new Scanner(Path.of("users.txt"), StandardCharsets.UTF_8)) {
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
}
Constructors without a Charset use the default charset. Since Java 18 (JEP 400) it is UTF-8 on every platform; in Java 17 and earlier it was the OS charset, for example windows-1252 on Western Windows. If the charset does not match the file, non-ASCII characters turn into garbage or reading silently stops. An explicit StandardCharsets.UTF_8 gives the same result on any version and machine. The Scanner(Path, Charset) constructor appeared in Java 10 and throws the checked IOException.
2. What do the Scanner methods tokens() and findAll() return?
What do the Scanner methods tokens() and findAll() return?
Both methods were added in Java 9 and connect Scanner with the Stream API. tokens() returns a Stream<String> of the remaining tokens (using the current delimiter), and findAll(String regex) returns a Stream<MatchResult> with every match of the pattern. They replace a manual while (hasNext()) loop when tokens have to be filtered, transformed or counted.
try (Scanner scanner = new Scanner("Total: 120 USD, 45 USD, 300 USD")) {
int total = scanner.findAll("\\d+")
.map(MatchResult::group)
.mapToInt(Integer::parseInt)
.sum(); // 465
}
The stream and the Scanner share one read position, so no other methods of that Scanner may be called until the terminal operation completes. Calling tokens() or findAll() on a closed Scanner throws IllegalStateException.
3. What is the Scanner method ioException() for?
What is the Scanner method ioException() for?
Scanner's reading methods do not rethrow IOException, they store it: on an I/O error hasNext() and hasNextLine() simply return false, so a broken read looks like a normal end of file. ioException() returns the last swallowed IOException, or null if there were no errors.
A typical case is a wrong charset: a Scanner created over a file with UTF-8 meets bytes in another encoding, the decoder throws MalformedInputException (a subclass of IOException), and the program processes only the beginning of the file without reporting an error. So check the result after the file-reading loop:
if (scanner.ioException() != null) {
throw scanner.ioException();
}
Scanner's own methods throw only unchecked exceptions: InputMismatchException, NoSuchElementException and IllegalStateException.
4. How do you read a hexadecimal or binary number with Scanner?
How do you read a hexadecimal or binary number with Scanner?
Pass the number base (radix) to the numeric method: nextInt(16), nextLong(2), hasNextInt(8). To avoid passing it on every call, set the radix for the whole Scanner with useRadix(); the default radix is 10.
try (Scanner scanner = new Scanner("ff 1010 777 0xff")) {
System.out.println(scanner.nextInt(16)); // 255
System.out.println(scanner.nextInt(2)); // 10
scanner.useRadix(8);
System.out.println(scanner.nextInt()); // 511
System.out.println(scanner.hasNextInt(16)); // false
}
Scanner does not understand the 0x prefix: the token "0xff" fails even hasNextInt(16). reset() restores radix 10, the default locale and the default delimiter, but does not change the read position.
5. How does Scanner differ from BufferedReader and Console, and when should you use each?
How does Scanner differ from BufferedReader and Console, and when should you use each?
Scanner (java.util) parses text into numbers and words right away (nextInt(), nextDouble(), regular expressions), but is slower on large files because every token is checked with a regular expression; its buffer is 1024 characters, it is not thread-safe, and it swallows I/O errors (available through ioException()). Good for small files and strings with numbers, config files, exercises.
BufferedReader (java.io) reads lines quickly with readLine() and an 8192-character buffer, but parses nothing: you need Integer.parseInt() or split() afterwards. Its methods are synchronized, and errors arrive as the checked IOException. The choice for logs, large files and speed-critical tasks.
Console (System.console()) is meant for an interactive terminal and can read a password without echoing it (readPassword()). It reports errors as IOError. If there is no terminal, for example when input is redirected from a file, System.console() returns null.