Рубрики
Без рубрики

Сканер Java hasNext() против hasNextLine()

Узнайте о различиях между методами hasNext() и hasNextLine() сканера Java.

Автор оригинала: baeldung.

1. Обзор

Класс Scanner – это удобный инструмент, который может анализировать примитивные типы и строки с использованием регулярных выражений и был введен в пакет java.util в Java 5.

В этом коротком уроке мы поговорим о его методах hasNext() и hasNextLine () . Хотя на первый взгляд эти два метода могут показаться довольно похожими, на самом деле они выполняют совершенно разные проверки.

Вы также можете прочитать больше о классе универсальных сканеров в кратком руководстве здесь .

2. hasNext()

2.1. Основное использование

Метод hasNext() проверяет, есть ли у Сканера другой токен на входе. //Сканер разбивает свой ввод на токены, используя шаблон разделителя, который по умолчанию соответствует пробелу . То есть hasNext() проверяет ввод и возвращает true , если он содержит другой символ, не являющийся пробелом.

Мы также должны отметить несколько деталей о разделителе по умолчанию:

  • Пробел включает в себя не только символ пробела, но и пробел табуляции ( \t ), ввод строки ( \n ) и еще больше символов
  • Непрерывные пробелы обрабатываются как один разделитель
  • Пустые строки в конце ввода не печатаются — то есть hasNext() возвращает false для пустых строк

Давайте рассмотрим пример того, как hasNext() работает с разделителем по умолчанию. Во-первых, мы подготовим входную строку, которая поможет нам изучить результат синтаксического анализа S canner :

String INPUT = new StringBuilder()
    .append("magic\tproject\n")
    .append("     database: oracle\n")
    .append("dependencies:\n")
    .append("spring:foo:bar\n")
    .append("\n")  // Note that the input ends with a blank line
    .toString();

Далее давайте проанализируем входные данные и распечатаем результат:

Scanner scanner = new Scanner(INPUT);
while (scanner.hasNext()) {
    log.info(scanner.next());
}
log.info("--------OUTPUT--END---------")

Если мы запустим приведенный выше код, мы увидим вывод консоли:

[DEMO]magic
[DEMO]project
[DEMO]database:
[DEMO]oracle
[DEMO]dependencies:
[DEMO]spring:foo:bar
[DEMO]--------OUTPUT--END---------

2.2. С Пользовательским Разделителем

До сих пор мы рассматривали hasNext() с разделителем по умолчанию. Сканер класс предоставляет useDelimiter(шаблон строки) метод , который позволяет нам изменять разделитель. Как только разделитель будет изменен, метод hasNext() выполнит проверку с новым разделителем вместо разделителя по умолчанию.

Давайте посмотрим еще один пример того, как hasNext() и next() работают с пользовательским разделителем. Мы повторно используем входные данные из последнего примера.

После того, как сканер проанализирует маркер, соответствующий строке ” зависимости: “, мы изменим разделитель на двоеточие ( 🙂 , чтобы мы могли анализировать и извлекать каждое значение зависимостей:

while (scanner.hasNext()) {
    String token = scanner.next();
    if ("dependencies:".equals(token)) {
        scanner.useDelimiter(":");
    }
    log.info(token);
}
log.info("--------OUTPUT--END---------");

Давайте посмотрим на полученный результат:

[DEMO]magic
[DEMO]project
[DEMO]database:
[DEMO]oracle
[DEMO]dependencies:
[DEMO]
spring
[DEMO]foo
[DEMO]bar


[DEMO]--------OUTPUT--END---------

Отлично! Мы успешно извлекли значения в ” зависимости “, однако есть некоторые неожиданные проблемы с разрывом строки . Мы увидим, как избежать этого в следующем разделе.

2.3. С регулярным выражением в качестве разделителя

Давайте рассмотрим результаты в последнем разделе. Во-первых, мы заметили, что перед ” весна “есть разрыв строки ( \n ). Мы изменили разделитель на ” : ” после того, как был получен токен “зависимости:” . Разрыв строки после ” зависимости: ” теперь становится частью следующего токена. Поэтому hasNext() вернул true и разрыв строки был распечатан.

По той же причине подача строки после ” hibernate “и последняя пустая строка становятся частью последнего маркера, поэтому две пустые строки выводятся вместе с” hibernate “.

Если мы сможем использовать двоеточие и пробел в качестве разделителя, то значения “зависимостей” будут правильно проанализированы, и наша проблема будет решена. Чтобы добиться этого, давайте изменим useDelimiter(“:”) вызов:

scanner.useDelimiter(":|\\s+");

:|\\s+ ” здесь является регулярным выражением, соответствующим одному “:” или одному или нескольким пробелам. С помощью этого исправления вывод превращается в:

[DEMO]magic
[DEMO]project
[DEMO]database:
[DEMO]oracle
[DEMO]dependencies:
[DEMO]spring
[DEMO]foo
[DEMO]bar
[DEMO]--------OUTPUT--END---------

3. hasNextLine()

То hasNextLine() метод проверяет, есть ли еще одна строка во входных данных Сканер объект, независимо от того, пуста строка или нет.

Давайте снова возьмем тот же ввод. На этот раз мы добавим номера строк перед каждой строкой во входных данных, используя методы hasNextLine() и nextLine() :

int i = 0;
while (scanner.hasNextLine()) {
    log.info(String.format("%d|%s", ++i, scanner.nextLine()));
}
log.info("--------OUTPUT--END---------");

Теперь давайте взглянем на наши результаты:

[DEMO]1|magic	project
[DEMO]2|     database: oracle
[DEMO]3|dependencies:
[DEMO]4|spring:foo:bar
[DEMO]5|
[DEMO]--------OUTPUT--END---------

Как мы и ожидали, номера строк напечатаны, и последняя пустая строка тоже там.

4. Заключение

В этой статье мы узнали, что метод Scanner ‘s hasNextLine() проверяет, есть ли другая строка во входных данных, независимо от того, пустая строка или нет, в то время как hasNext() использует разделитель для проверки другого токена.

Как всегда, полный исходный код примеров доступен на GitHub.