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

Обзор метода next класса Scanner
Раздел: Сканирование ввода (Scanner)
Scanner.next: String

Описание метода Scanner.next

Метод next() класса java.util.Scanner возвращает следующий токен входного потока в виде строки. Токен определяется текущим разделителем (по умолчанию это пробельные символы). Метод считывает до следующего разделителя и возвращает найденную подстроку.

Когда используется: при поэтапном разборе потоков текста, когда требуется получить отдельные слова, числа в виде строк или куски данных, разделённые заданным шаблоном.

Аргументы и перегрузки: сам next() не принимает аргументов. В API Scanner доступны родственные методы, которые принимают шаблоны:

  • next(Pattern pattern) - возвращает следующий токен, соответствующий переданному регулярному выражению.
  • next(String pattern) - аналогично принимает строковый вид шаблона и ищет следующий токен по этому шаблону.

Возвращаемое значение: String - текст следующего найденного токена без разделителей.

Поведение и исключения:

  • Если токенов нет - выбрасывается NoSuchElementException.
  • Если сканер закрыт - выбрасывается IllegalStateException.
  • Для разбора чисел существуют отдельные методы (nextInt, nextDouble и т. п.) - при их использовании возможна InputMismatchException, если токен не соответствует ожидаемому числовому формату.

Особенности: разбиение на токены регулируется через метод useDelimiter(Pattern) или useDelimiter(String). Метод next() читает только до разделителя и не возвращает сам разделитель; в отличие от nextLine(), который возвращает остаток строки до символа новой строки.

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

Примеры показывают поведение метода next() с разными входными данными и шаблонами.

1) Базовое чтение токенов из строки:

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner("Hello World 123");
        System.out.println(sc.next());
        System.out.println(sc.next());
        System.out.println(sc.next());
        sc.close();
    }
}
Hello
World
123

2) Различие next() и nextLine():

import java.util.Scanner;

class A {
    public static void main(String[] args) {
        Scanner sc = new Scanner("First line\nSecond line");
        System.out.println("next(): '" + sc.next() + "'");
        System.out.println("nextLine(): '" + sc.nextLine() + "'");
        sc.close();
    }
}
next(): 'First'
nextLine(): ' line'

3) Использование шаблона с next(Pattern):

import java.util.Scanner;
import java.util.regex.Pattern;

class B {
    public static void main(String[] args) {
        Scanner sc = new Scanner("abc123xyz 456");
        System.out.println(sc.next(Pattern.compile("[a-z]+[0-9]+")));
        sc.close();
    }
}
abc123

Альтернативы в Java и особенности

Несколько альтернатив для ввода и разбора данных в Java:

  • BufferedReader.readLine() - считывает строчки целиком. Предпочтительнее для построчной обработки больших объёмов и при необходимости высокой производительности. Возвращает строку или null при окончании потока.
  • Console.readLine() - удобен для интерактивного ввода в консоли (ищет системную консоль). Не всегда доступен (например, в IDE).
  • StringTokenizer - устаревший утилитарный класс для разбиения строк; проще, но менее гибкий и не рекомендуется для новых решений.
  • StreamTokenizer - более низкоуровневый разбор, даёт контроль над лексемами, полезен при парсинге с нестандартной грамматикой.

Выбор: если нужен простой разбор на слова - Scanner удобен; для скорости и обработки больших файлов - BufferedReader; для ввода паролей или безопасного ввода - Console; для сложного лексического анализа - StreamTokenizer или собственный парсер.

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

Краткие примеры эквивалентов метода next() в других языках и их отличия.

PHP - чтение токенов из строки с strtok или explode:

$s = "Hello World 123";
$tok = strtok($s, " ");
while ($tok !== false) {
    echo $tok . PHP_EOL;
    $tok = strtok(" ");
}
Hello
World
123

JavaScript (Node.js) - разбить строку по пробелам:

const s = 'Hello World 123';
const tokens = s.split(/\s+/);
console.log(tokens.join('\n'));
Hello
World
123

Python - split или итерация по sys.stdin:

s = 'Hello World 123'
for tok in s.split():
    print(tok)
Hello
World
123

C# - Scanner-аналоги: String.Split или TextReader: простой пример:

using System;

class P { static void Main(){
    string s = "Hello World 123";
    foreach(var t in s.Split((char[])null, StringSplitOptions.RemoveEmptyEntries))
        Console.WriteLine(t);
}}
Hello
World
123

Go - fmt.Fscan / bufio.Scanner:

package main
import (
    "bufio"
    "fmt"
    "strings"
)
func main(){
    s := "Hello World 123"
    sc := bufio.NewScanner(strings.NewReader(s))
    sc.Split(bufio.ScanWords)
    for sc.Scan() {
        fmt.Println(sc.Text())
    }
}
Hello
World
123

Kotlin - использует тот же Scanner или split:

fun main(){
    val s = "Hello World 123"
    s.split(Regex("\\s+")).forEach { println(it) }
}
Hello
World
123

Lua - использование ipairs по результату split (через внешний код):

local s = "Hello World 123"
for w in s:gmatch("%S+") do
  print(w)
end
Hello
World
123

Особенности: во многих языках работа с токенами делегируется методам строки (split, gmatch) или специализированным сканерам; отличие от Java: в Java Scanner объединяет чтение из разных источников и разбор токенов в одном классе.

Типичные ошибки при использовании

Основные ошибки и примеры.

1) Попытка читать, когда токенов нет - NoSuchElementException:

import java.util.Scanner;

class E1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner("");
        System.out.println(sc.next());
    }
}
Exception in thread "main" java.util.NoSuchElementException
    at java.base/java.util.Scanner.throwFor(Scanner.java:937)
    at java.base/java.util.Scanner.next(Scanner.java:1594)
    ...

Рекомендация: перед вызовом next() проверять hasNext().

2) Использование next() после nextInt()/nextDouble() без обработки остатка строки:

import java.util.Scanner;

class E2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner("10\nrest");
        int n = sc.nextInt();
        String s = sc.nextLine();
        System.out.println("n=" + n);
        System.out.println("s='" + s + "'");
    }
}
n=10
s=''

Пояснение: nextInt() не потребляет символ новой строки, поэтому следующий вызов nextLine() вернёт пустую строку. Решение - добавить sc.nextLine() для пропуска остатка.

3) Закрытие сканера, читающего System.in, приводит к закрытию потока System.in и последующим ошибкам при попытке чтения:

Scanner sc = new Scanner(System.in);
sc.close();
// далее попытки чтения из System.in вызовут ошибки
(последующие операции ввода могут выбросить IllegalStateException или вести к невозможности чтения)

4) Ошибки при использовании nextInt вместо next при некорректном формате - InputMismatchException:

Scanner sc = new Scanner("abc");
sc.nextInt();
Exception in thread "main" java.util.InputMismatchException
    at java.base/java.util.Scanner.throwFor(Scanner.java:937)
    ...

Изменения и эволюция

Метод next() как поведение токенизации оставался стабильным в новых релизах Java. Основные изменения в классе Scanner за последние версии касались конструкторов, поддержки указания Charset при создании сканера, а также исправлений производительности и багов в разборе Unicode и регулярных выражений. Никаких радикальных изменений в семантике next() не происходило.

Расширенные и необычные примеры

1) Пользовательский разделитель (например, запятая или точка с запятой):

Пример java
import java.util.Scanner;

class Adv1 {
    public static void main(String[] args) {
        Scanner sc = new Scanner("a,b;c,d");
        sc.useDelimiter("[;,]");
        while (sc.hasNext()) System.out.println(sc.next());
        sc.close();
    }
}
a
b
c
d

2) Парсинг чисел с учетом локали (десятичный разделитель):

Пример java
import java.util.Locale;
import java.util.Scanner;

class Adv2 {
    public static void main(String[] args) {
        Scanner sc = new Scanner("3,14 2.71");
        sc.useLocale(Locale.FRANCE); // ожидает ',' для десятичной части
        System.out.println(sc.nextDouble());
        sc.useLocale(Locale.US);
        System.out.println(sc.nextDouble());
        sc.close();
    }
}
3.14
2.71

3) Поиск токена, соответствующего регулярному выражению, с помощью next(Pattern):

Пример java
import java.util.Scanner;
import java.util.regex.Pattern;

class Adv3 {
    public static void main(String[] args) {
        Scanner sc = new Scanner("id:42 name:john id:100");
        Pattern idPat = Pattern.compile("id:\\d+");
        while (sc.hasNext()) {
            if (sc.hasNext(idPat)) {
                System.out.println(sc.next(idPat));
            } else {
                sc.next(); // пропустить токен
            }
        }
        sc.close();
    }
}
id:42
id:100

4) Чтение больших файлов: сочетание BufferedReader и Scanner - антишаблон. Пример замедления при использовании Scanner для больших данных и альтернатива на BufferedReader:

Пример java
// Антипаттерн: миллионы вызовов next() могут быть медленными
Scanner sc = new Scanner(new java.io.File("big.txt"));
while (sc.hasNext()) {
    String tok = sc.next();
}
// Лучше: BufferedReader + ручная обработка строк
(практика показывает значительную разницу в скорости и потреблении памяти)

5) Комбинация next(Pattern) для сложного извлечения данных (пример извлечения пар key=value, где value может содержать пробелы, ограниченные кавычками):

Пример java
import java.util.Scanner;
import java.util.regex.Pattern;

class Adv5 {
    public static void main(String[] args) {
        String s = "k1=val k2=\"multi word\" k3=123";
        Scanner sc = new Scanner(s);
        Pattern pair = Pattern.compile("\\w+=\\\"[^\\\"]+\\\"|\\w+=[^\\s]+");
        while (sc.hasNext()) {
            if (sc.hasNext(pair)) System.out.println(sc.next(pair));
            else sc.next();
        }
        sc.close();
    }
}
k1=val
k2="multi word"
k3=123

6) Параллельное использование нескольких Scanner на одном InputStream - рискованно: внутренние буферы могут конфликтовать. Для многопоточной работы следует использовать синхронизацию и отдельные независимые потоки/ридеры.

джава Scanner.next function comments

En
Scanner.next Finds and returns the next complete token from this scanner