Пользовательский ввод в Java с Scanner
Чтение ввода с консоли в Java через класс Scanner — nextInt, nextDouble, nextLine и валидация ввода.
Для большинства начинающих программистов самый простой способ читать ввод с клавиатуры — это java.util.Scanner. Он оборачивает System.in (стандартный поток ввода) и предоставляет методы nextInt, nextDouble и nextLine. В этой главе рассматриваются API Scanner, известная проблема «Scanner пропускает строку» и альтернативы, когда Scanner перестаёт подходить.
Создание Scanner
Scanner находится в пакете java.util, поэтому нужен import:
import java.util.Scanner;
public class Greeter {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("What is your name? ");
String name = in.nextLine();
System.out.println("Hello, " + name + "!");
}
}Scanner следует закрывать после использования — но если закрыть scanner над System.in, стандартный ввод будет закрыт для всей программы. В коротких скриптах можно пропустить close(). В более длинном коде используйте try-with-resources для scanner'ов над файлами, но не для System.in.
Методы чтения
| Метод | Читает |
|---|---|
nextLine() | остаток текущей строки (без \n) |
next() | следующий токен, разделённый пробелами |
nextInt() | следующий токен, разобранный как int |
nextLong() | …как long |
nextDouble() | …как double |
nextBoolean() | …как boolean |
hasNext() | true, если доступен ещё один токен |
hasNextInt() | true, если следующий токен является корректным int |
hasNextLine() | true, если доступна ещё одна строка |
Используйте варианты hasNext... для проверки ввода перед его считыванием.
Полный цикл запросов
import java.util.Scanner;
public class Calculator {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("First number: ");
double a = in.nextDouble();
System.out.print("Second number: ");
double b = in.nextDouble();
System.out.println("Sum: " + (a + b));
}
}Если пользователь вводит не число, nextDouble бросает InputMismatchException. Обработку этого мы рассмотрим ниже.
Классическая проблема — nextInt оставляет символ новой строки
После nextInt() или nextDouble() scanner оставляет завершающий символ новой строки в буфере. Следующий вызов nextLine() вернёт пустую строку:
System.out.print("age? ");
int age = in.nextInt(); // user types "30" then Enter
System.out.print("name? ");
String name = in.nextLine(); // returns "" — the leftover newline
String name2 = in.nextLine(); // returns the typed nameДва распространённых способа исправить это:
- После
nextInt()/nextDouble()вызывайтеin.nextLine(), чтобы сбросить остаток строки. - Используйте
nextLine()везде и разбирайте строку самостоятельно:
System.out.print("age? ");
int age = Integer.parseInt(in.nextLine().trim());Второй стиль становится чище, когда нужна валидация.
Валидация с hasNext...
Scanner in = new Scanner(System.in);
System.out.print("Enter a number: ");
while (!in.hasNextInt()) {
System.out.print("That isn't an integer. Try again: ");
in.next(); // discard the bad token
}
int value = in.nextInt();
System.out.println("You entered: " + value);Чтение до конца файла
Распространённый шаблон пакетной обработки — читать, пока пользователь не нажмёт Ctrl+D (Linux/macOS) или Ctrl+Z затем Enter (Windows):
Scanner in = new Scanner(System.in);
int total = 0;
while (in.hasNextInt()) {
total += in.nextInt();
}
System.out.println("Total: " + total);BufferedReader — когда Scanner недостаточно быстр
Для соревновательного программирования или при чтении десятков тысяч строк BufferedReader значительно быстрее Scanner:
import java.io.BufferedReader;
import java.io.InputStreamReader;
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = br.readLine();
int n = Integer.parseInt(line.trim());Кода чуть больше, но ускорение в 10–20 раз — обычное дело.
System.console() — только для интерактивных сессий
Когда программа подключена к реальному терминалу, System.console() возвращает объект Console с readLine и readPassword (который не отображает символы):
java.io.Console c = System.console();
if (c != null) {
String user = c.readLine("Username: ");
char[] pass = c.readPassword("Password: ");
// ... use pass ...
java.util.Arrays.fill(pass, ' '); // zero out the password buffer
}System.console() возвращает null, когда программа запускается через IDE, перенаправляющую stdin, поэтому не полагайтесь на него для общего ввода.
Демонстрация
Приведённый ниже запускаемый код использует System.in. Поскольку runner не поддерживает интерактивный ввод, в этой версии чтение идёт из фиксированной строки — что близко к обычному использованию Scanner:
Что дальше
Часть 2 на этом завершается. Следующая часть, Управление потоком, начинается с Java if, else и else if и продолжается switch и циклами, которые лежат в основе большинства программной логики.