Java Scanner hasNext() vs. hasNextLine() – Java 扫描器 hasNext() vs. hasNextLine()

最后修改: 2019年 10月 28日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

The Scanner class is a handy tool that can parse primitive types and strings using regular expressions and was introduced into the java.util package in Java 5.

Scanner类是一个方便的工具,可以使用正则表达式解析原始类型和字符串,在Java 5中被引入java.util包。

In this short tutorial, we’ll talk about its hasNext() and hasNextLine() methods. Even though these two methods may look pretty similar at first, they’re actually doing quite different checks.

在这个简短的教程中,我们将讨论其hasNext() hasNextLine() 方法。尽管这两个方法起初看起来很相似,但它们实际上是在做相当不同的检查。

You can also read more about the versatile Scanner class in the quick guide here.

你也可以在这里的快速指南中阅读更多关于多功能扫描器类的信息

2. hasNext()

2.hasNext()

2.1. Basic Usage

2.1.基本用途

The hasNext() method checks if the Scanner has another token in its input. A Scanner breaks its input into tokens using a delimiter pattern, which matches whitespace by default. That is, hasNext() checks the input and returns true if it has another non-whitespace character.

hasNext()方法检查Scanner的输入中是否有另一个token。一个Scanner使用一个分隔符模式将其输入分成多个标记,该模式默认匹配whitespace也就是说,hasNext()检查输入,如果有另一个非whitespace字符则返回

We should also note a few details about the default delimiter:

我们还应该注意关于默认分隔符的一些细节。

  • Whitespace includes not only the space character, but also tab space (\t), line feed (\n), and even more characters
  • Continuous whitespace characters are treated as a single delimiter
  • The blank lines at the end of the input are not printed — that is, hasNext() returns false for blank lines

Let’s take a look at an example of how hasNext() works with the default delimiter. First, we’ll prepare an input string to help us explore Scanner‘s parsing result:

让我们来看一个例子,看看hasNext() 如何在默认的分隔符下工作。首先,我们将准备一个输入字符串,以帮助我们探索Scanner的解析结果。

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();

Next, let’s parse the input and print the result:

接下来,我们来解析输入并打印结果。

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

If we run the above code, we’ll see the console output:

如果我们运行上述代码,我们会看到控制台的输出。

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

2.2. With Custom Delimiter

2.2.带有自定义分隔符

So far, we’ve looked at hasNext() with the default delimiter. The Scanner class provides a useDelimiter(String pattern) method that allows us to change the delimiter. Once the delimiter is changed, the hasNext() method will do the check with the new delimiter instead of the default one.

到目前为止,我们已经研究了使用默认定界符的hasNext()Scanner提供了一个useDelimiter(String pattern)方法,允许我们改变定界符。一旦分隔符被改变,hasNext()方法将用新的分隔符而不是默认的分隔符进行检查。

Let’s see another example of how hasNext() and next() work with a custom delimiter. We’ll reuse the input from the last example.

让我们看看另一个例子,看看hasNext() next() 如何与自定义分隔符一起工作。我们将重新使用上一个例子中的输入。

After the scanner parses a token matching the string “dependencies:“, we’ll change the delimiter to a colon ( : ) so that we can parse and extract each value of the dependencies:

在扫描器解析出与字符串”dependencies:“相匹配的标记后,我们将把分隔符改为冒号(:),这样我们就可以解析并提取依赖关系的每个值。

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

Let’s see the resulting output:

让我们看看结果的输出。

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


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

Great! We’ve successfully extracted the values in “dependencies“, however, there are some unexpected line-break problems. We’ll see how to avoid those in the next section.

很好!我们已经成功地提取了”dependencies“中的值,然而,有一些意外的换行问题。我们将在下一节中看到如何避免这些问题。

2.3. With regex as Delimiter

2.3.用regex作为分隔符

Let’s review the output in the last section. First, we noticed that there’s a line break (\n) before “spring“. We’ve changed the delimiter to “:” after the “dependencies:” token was fetched. The line break after the “dependencies:” now becomes the part of the next token. Therefore, hasNext() returned true and the line break was printed out.

让我们回顾一下上一节中的输出。首先,我们注意到在”spring“之前有一个换行符(n)。我们把“dependencies: “后面的分隔符改成了”:“。:token被取走了。在”dependencies:“之后的换行符现在成为下一个标记的一部分。因此,hasNext() 返回true,断行被打印出来。

For the same reason, the line feed after “hibernate” and the last blank line become the part of the last token, so two blank lines are printed out together with “hibernate“.

出于同样的原因,”hibernate“之后的换行和最后一个空行成为最后一个标记的一部分,所以两个空行和”hibernate“一起被打印出来。

If we can make both colon and whitespace as the delimiter, then the “dependencies” values will be correctly parsed and our problem will be solved. To achieve that, let’s change the useDelimiter(“:”) call:

如果我们能把冒号和空格都作为分隔符,那么 “依赖 “值将被正确解析,我们的问题也就解决了。为了实现这一点,让我们改变useDelimiter(“:”)调用。

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

The “:|\\s+” here is a regular expression matching a single “:” or one or more whitespace characters. With this fix, the output turns into:

这里的”:|\s+“是一个匹配单个”: “或一个或多个空白字符的正规表达式。通过这个修正,输出结果变成了。

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

3. hasNextLine()

3.hasNextLine()

The hasNextLine() method checks to see if there’s another line in the input of the Scanner object, no matter if the line is blank or not.

hasNextLine()方法检查Scanner对象的输入中是否有另一行,无论该行是否为空白。

Let’s take the same input again. This time, we’ll add line numbers in front of each line in the input using hasNextLine() and nextLine() methods:

让我们再来看看同样的输入。这一次,我们将使用hasNextLine()nextLine()方法在输入的每一行前面添加行号。

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

Now, let’s take a look at our output:

现在,让我们看一下我们的输出。

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

As we expected, the line numbers are printed, and the last blank line is there, too.

正如我们所期望的那样,行号被打印出来,而且最后一个空行也在那里。

4. Conclusion

4.总结

In this article, we’ve learned that Scanner‘s hasNextLine() method checks if there is another line in the input, no matter if the line is blank or not, while hasNext() uses a delimiter to check for another token.

在这篇文章中,我们已经了解到,ScannerhasNextLine()方法会检查输入中是否有另一行,无论该行是否为空白,而hasNext()则使用一个分隔符来检查另一个标记。

As always, the complete source code for the examples is available over on GitHub.

一如既往,例子的完整源代码可在GitHub上获得