Перейти к основному содержимому

Java Scanner hasNext() против hasNextLine()

· 4 мин. чтения

1. Обзор

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

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

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

2. имеетСледующий()

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() с разделителем по умолчанию. Класс Scanner предоставляет метод `` useDelimiter (String pattern) , который позволяет нам изменить разделитель. После изменения разделителя метод 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 ) перед словом spring . Мы изменили разделитель на « : » после получения токена «dependencies:» . Разрыв строки после « зависимостей: » теперь становится частью следующего токена. Поэтому функция 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() проверяет, есть ли другая строка во входных данных объекта Scanner , независимо от того, пуста эта строка или нет.

Давайте снова возьмем тот же ввод. На этот раз мы добавим номера строк перед каждой строкой ввода, используя методы 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. Вывод

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

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