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.