【问题标题】:How can the hasNext methods of Scanner "not advance past any input"?Scanner 的 hasNext 方法如何“不超过任何输入”?
【发布时间】:2020-03-10 18:00:04
【问题描述】:

java.util.ScannerhasNexthasNextXxx 方法中显示:

如果此扫描器在其输入中有另一个令牌,则返回 true。此方法可能会在等待输入扫描时阻塞。 扫描仪不会超过任何输入。

扫描器如何在明确必须检查输入中是否存在下一个标记(如ReadableInputStream)时不通过输入流?

【问题讨论】:

  • peek()是不是同一个概念
  • 您是指 Lambda 流 API 中使用的 peek
  • 是的,我的第一个想法是这样的
  • 我猜是一回事,但我希望peek 没有同样的文档错误(或者至少是写得很糟糕的陈述)。

标签: java java.util.scanner inputstream system.in


【解决方案1】:

这里有两个“通过输入推进”的概念。

第一个概念是从 InputStream 读取更多字节,当然 Scanner 必须这样做以测试它是否有下一个令牌。 Scanner 通过缓冲从 InputStream 读取的新字节来实现这一点,以便以后可以在必要时从 Scanner 读取这些字节。我们可以称之为“通过输入流前进”。

第二个概念是从缓冲区中推进要消耗的下一个字节的位置。当您调用像 next 这样使用令牌的方法来标记这些字节已被“使用”并且不应再次读取时,就会发生这种情况;调用next 会推进缓冲区中的位置。我们可以称之为“通过扫描器缓冲区中的输入前进”。

文档中的声明“扫描仪不会超过任何输入”是第二个概念;调用hasNext 不会通过扫描器的缓冲区,它只是从输入流中读取更多字节到缓冲区中。为了验证这一点,您可以尝试创建一个输入流,调用hasNext,然后使用nextInLine 读取下一个字符(而不是下一个标记):

> InputStream is = new ByteArrayInputStream("hello world".getBytes());
> Scanner sc = new Scanner(is);
> sc.next()
"hello" (String)
> sc.hasNext()
true (boolean)
> sc.nextInLine(".")
" " (String)

所以调用hasNext 不仅不会消耗下一个标记,而且也不会消耗下一个标记之前的分隔符。从这个意义上说,扫描器没有“前进[d] 超过任何输入”

【讨论】:

    【解决方案2】:

    确实在输入流中前进。从ScannerScanner 用户的角度来看,它只是不会超过下一个输入。所以可以说,这段文档措辞不当。

    这可以很容易地通过将单个标记放入流中进行测试,然后为该标记调用hasNext。在这种情况下,您会发现调用hasNext 后流已耗尽。

    换句话说,Scanner 在内部缓冲偷看的字符,包括任何分隔符。随后的调用将从缓冲的字符开始。 Scanner 不依赖底层流提供的任何缓冲。

    此文本至少在 Java 12 之前存在。

    示例代码:

    Reader stringReader = new StringReader("Single line");
    
    Scanner firstScanner = new Scanner(stringReader);
    // prints out true because there is a first line
    System.out.println(firstScanner.hasNextLine());
    
    Scanner secondScanner = new Scanner(stringReader);
    // prints out false because the scanner has advanced the reader
    // ... through the character stream generated from the string
    System.out.println(secondScanner.hasNextLine());
    
    // prints out true because the first scanner is buffering the input
    System.out.println(firstScanner.hasNextLine());
    

    它还包含 hasNext 的其他文档问题,例如在 Scanner 类本身的文档中它写道:

    next()hasNext() 方法及其配套方法(例如 nextInt()hasNextInt())首先跳过任何与分隔符模式匹配的输入,然后尝试返回下一个标记强>。

    显然最后一部分对于hasNext() 是不正确的。这看起来像 hasNext 已被硬塞到现有的句子中。

    【讨论】:

    • 你怎么会提出问题并回答呢?
    • @ZOLDIK 我首先在 SO 上搜索,然后没有找到信息。所以我决定测试它并写一个问题和答案。我猜下一步是针对文档提交错误报告。当然,请随意写一个更好的答案,我很乐意接受它:)
    • 我不认为这是真的;例如Scanner sc = new Scanner("Hello world"); sc.next(); sc.hasNext(); sc.findInLine(".") 最后一次调用返回" ",而不是"w",因此hasNext 调用不会将输入推进到下一个令牌的开头。
    • 我认为您完全错过了问题和答案的“输入流”部分。字符串不是流,不包含任何状态。如果您在重新阅读后对问题或答案的更改有任何建议,我很乐意将其考虑在内。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-27
    • 2013-03-28
    • 1970-01-01
    • 1970-01-01
    • 2012-05-16
    相关资源
    最近更新 更多