Scanner.nextLine: примеры (JAVA)

Чтение строк в Java с помощью nextLine
Раздел: Сканирование ввода (Scanner)
Scanner.nextLine: String

Описание метода nextLine

Метод Scanner.nextLine() в Java возвращает оставшуюся часть текущей строки ввода как объект String, исключая символы-разделители строк. После вызова сканер продвигается за символы конца строки. Параметров у метода нет. Возвращаемое значение - строка с содержимым до ближайшего разделителя строки. Если входной поток завершён и строк для чтения нет, вызов nextLine() приводит к NoSuchElementException. Если экземпляр Scanner уже закрыт, будет выброшено IllegalStateException.

Поведение и особенности:

  • Метод читает до первой последовательности символов-разделителей строки. Разделители определяются внутренним регулярным выражением, эквивалентным \R, поэтому поддерживаются CR, LF и CRLF.
  • Возвращаемая строка не содержит символы разделителя строки.
  • Метод блокируется до тех пор, пока не встретит завершение строки или EOF.
  • nextLine() игнорирует текущий разделитель токенов (useDelimiter) и всегда ориентируется на границы строк.
  • Для проверки наличия следующей строки перед чтением применяется hasNextLine().
  • Кодировка ввода задаётся при создании сканера, например new Scanner(InputStream, "UTF-8"). При чтении из файлов можно использовать конструктор с Path и кодировкой.

Типичные исключения: NoSuchElementException - чтение после EOF; IllegalStateException - сканер закрыт.

Короткие примеры использования

Ниже примеры кода с результатами. В блоках кода класс для примера указан как pre class="ex_c", результат - pre class="ex_r".

1) Чтение одной строки из консоли:

import java.util.Scanner;

public class Example1 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String line = scanner.nextLine();
        System.out.println("Введено: " + line);
        scanner.close();
    }
}
Ввод:
Hello world
Результат:
Введено: Hello world

2) Чтение нескольких строк до пустой строки:

Scanner scanner = new Scanner(System.in);
while (scanner.hasNextLine()) {
    String s = scanner.nextLine();
    if (s.isEmpty()) break;
    System.out.println("Line: " + s);
}
scanner.close();
Ввод:
one
two

Результат:
Line: one
Line: two

3) Частая ошибка при комбинировании nextInt() и nextLine():

Scanner sc = new Scanner(System.in);
System.out.println("Введите число:");
int x = sc.nextInt();
System.out.println("Введите строку:");
String s = sc.nextLine(); // часто возвращает пустую строку
System.out.println("s='" + s + "'");
sc.close();
Ввод:
42
hello
Результат:
s=''
(пояснение: после nextInt() в буфере остался символ новой строки)

4) Исправление ошибки: дополнительный nextLine() или skip:

Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
sc.nextLine(); // пропустить остаток строки
String s = sc.nextLine();
Ввод:
42
hello
Результат:
s='hello'

5) Чтение файла в UTF-8:

import java.nio.file.Paths;
import java.util.Scanner;

Scanner sc = new Scanner(Paths.get("file.txt"), "UTF-8");
while (sc.hasNextLine()) {
    System.out.println(sc.nextLine());
}
sc.close();
Результат: вывод строк файла без символов конца строки

Схожие методы в Java и их особенности

  • BufferedReader.readLine() - возвращает null при EOF, работает быстрее при большом объёме текста, удобно для построчного чтения из Reader.
  • Console.readLine() - удобен для интерактивного ввода в терминале, поддерживает чтение пароля через readPassword. Console может быть недоступен в средах без консоли (IDE).
  • Files.lines(Path) - возвращает поток строк Stream<String>, эффективен для обработки больших файлов с ленивыми операциями.
  • Scanner.next() - возвращает следующий токен по текущему разделителю (по умолчанию пробельный); полезен для разбора слов, но не читает пробелы внутри строки.

Выбор зависит от задачи: для простого построчного ввода подходит nextLine() или BufferedReader. Для потоковой обработки больших файлов предпочтительнее Files.lines. Для разбора токенов используется Scanner.next().

Аналоги в других языках и отличия

  • Python: input() или sys.stdin.readline(). input() возвращает строку без символа конца строки; блокирует до ввода. Пример:
    s = input()
    print('s="' + s + '"')
    Ввод:
    Hello
    Результат:
    s="Hello"
  • JavaScript (Node.js): модуль readline. Пример:
    const rl = require('readline').createInterface({ input: process.stdin, output: process.stdout });
    rl.on('line', (line) => { console.log('s="' + line + '"'); rl.close(); });
    Ввод:
    Hello
    Результат:
    s="Hello"
  • PHP: fgets(STDIN) возвращает строку с символом конца строки; часто применяется rtrim() для удаления. Пример:
    $s = fgets(STDIN);
    $s = rtrim($s, "\r\n");
    echo "s=\"$s\"\n";
    Ввод:
    Hello
    Результат:
    s="Hello"
  • C#: Console.ReadLine() возвращает строку без символа конца строки или null на EOF.
    string s = Console.ReadLine();
    Console.WriteLine($"s=\"{s}\"");
    Ввод:
    Hello
    Результат:
    s="Hello"
  • Go: bufio.NewReader(os.Stdin).ReadString('\n') возвращает строку, включая разделитель; для удаления используется strings.TrimSuffix.
    r := bufio.NewReader(os.Stdin)
    s, _ := r.ReadString('\n')
    s = strings.TrimRight(s, "\r\n")
    fmt.Println("s=\"" + s + "\"")
    Ввод:
    Hello
    Результат:
    s="Hello"
  • Kotlin: readLine() возвращает строку без символа конца строки или null при EOF. Поведение близко к Python и C#.
  • Lua: io.read() читает строку без конца строки по умолчанию.
  • SQL: понятие построчного чтения не применяется в языке запросов. Чтение входа выполняется средствами клиентской библиотеки.

Отличия от Java: в большинстве языков возвращается null или строка без разделителя, но механика блокировки, обработка EOF и доступность консоли могут отличаться. В Java при отсутствии строки бросается исключение, поэтому перед вызовом удобно использовать hasNextLine().

Типичные ошибки и примеры

  • Пустая строка после чтения числа: оставшийся символ новой строки после nextInt() делает первый nextLine() пустым. Пример: см. раздел примеров выше. Решения: вызвать дополнительный nextLine() или использовать skip("\\R").
  • Чтение после EOF приводит к NoSuchElementException:
Scanner sc = new Scanner("a\nb");
sc.nextLine(); // "a"
sc.nextLine(); // "b"
sc.nextLine(); // NoSuchElementException
Результат: выбрасывается java.util.NoSuchElementException на третьем вызове
  • Вызов после закрытия сканера вызывает IllegalStateException:
Scanner sc = new Scanner(System.in);
sc.close();
sc.nextLine(); // IllegalStateException
Результат: java.lang.IllegalStateException: Scanner closed
  • Проблемы с кодировкой при чтении из InputStream без указания кодировки; при использовании конструкторов с кодировкой рекомендуется явно указывать "UTF-8".
  • Ожидание ввода в средах без интерактивной консоли (IDE) может выглядеть как зависание программы.

Изменения и стабильность поведения

Класс Scanner и метод nextLine() введены в Java 5 (JDK 1.5) и с тех пор поведение метода остаётся стабильным. Документация уточняла распознавание разделителей строк через регулярное выражение, совместимое с \R, что обеспечивает корректную работу с CR, LF и CRLF во всех современных версиях JVM. В последних релизах изменений API самого метода не наблюдалось; улучшения в JVM и библиотеке касаются производительности и исправления мелких багов в реализации регулярных выражений.

Расширенные и редкие сценарии применения

1) Чтение строки из сокета (InputStream) построчно:

Пример java
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

try (ServerSocket ss = new ServerSocket(5555)) {
    Socket s = ss.accept();
    Scanner sc = new Scanner(s.getInputStream(), "UTF-8");
    while (sc.hasNextLine()) {
        String line = sc.nextLine();
        // обработка
    }
    sc.close();
}
Результат: получение текстовых линий от клиента; важно закрывать ресурсы и учитывать блокировки

2) Использование skip для аккуратного пропуска символа новой строки:

Пример java
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
try { sc.skip("\\R"); } catch (java.util.NoSuchElementException e) { /* нет разделителя */ }
String rest = sc.nextLine();
Пояснение: skip("\\R") удаляет один разделитель строки, если он там есть, избегая пустой строки от nextLine()

3) Чтение блока до специального маркера (например, "END"):

Пример java
Scanner sc = new Scanner(System.in);
StringBuilder sb = new StringBuilder();
while (sc.hasNextLine()) {
    String line = sc.nextLine();
    if ("END".equals(line)) break;
    sb.append(line).append(System.lineSeparator());
}
System.out.println("Получено:\n" + sb.toString());
sc.close();
Ввод:
first
second
END
Результат:
Получено:
first
second

4) Парсинг многострочного блока в объекты с помощью регулярных шаблонов:

Пример java
String input = "name:John\nage:30\ncity:NY\n";
Scanner sc = new Scanner(input);
while (sc.hasNextLine()) {
    String line = sc.nextLine();
    String[] parts = line.split(":", 2);
    if (parts.length == 2) {
        System.out.printf("key=%s val=%s%n", parts[0], parts[1]);
    }
}
sc.close();
Результат:
key=name val=John
key=age val=30
key=city val=NY

5) Быстрое подсчитывание строк в большом файле (альтернатива nextLine - Files.lines):

Пример java
long count = 0;
try (Scanner sc = new Scanner(Paths.get("big.txt"), "UTF-8")) {
    while (sc.hasNextLine()) { sc.nextLine(); count++; }
}
System.out.println(count);
Результат: количество строк; для очень больших файлов чаще предпочтительнее Streams API и параллельная обработка

джава Scanner.nextLine function comments

En
Scanner.nextLine Advances this scanner past the current line and returns the input that was skipped