【发布时间】:2017-10-21 21:11:27
【问题描述】:
这是来自Java的Scanner next()方法的解释:
此方法在等待输入扫描时可能会阻塞,即使一个 之前调用 hasNext() 返回 true。
如果调用 hasNext(),该方法如何等待用户输入?如果我们调用 hasNext() 并且它返回 true,我们知道有下一个标记,那么 next() 方法是如何以及为什么这样做的呢?
【问题讨论】:
这是来自Java的Scanner next()方法的解释:
此方法在等待输入扫描时可能会阻塞,即使一个 之前调用 hasNext() 返回 true。
如果调用 hasNext(),该方法如何等待用户输入?如果我们调用 hasNext() 并且它返回 true,我们知道有下一个标记,那么 next() 方法是如何以及为什么这样做的呢?
【问题讨论】:
您需要阅读方法的完整documentation:
从此扫描器中查找并返回下一个完整令牌。一个 完整的令牌之前和之后是匹配的输入 分隔符模式。此方法可能会在等待输入时阻塞 扫描,即使之前调用 hasNext() 返回 true。
当有另一个令牌时,Scanner#hasNext 方法 (documentation) 可能会返回 true。但根据分隔符模式,令牌可能尚未被视为完成,Scanner#next 将始终阻塞,直到令牌完成。
如果Scanner 中有完整令牌,那么Scanner#next 将立即返回并且不会阻止。
您可以使用Scanner#useDelimiter 方法设置分隔符模式 (documentation)
如果您没有设置特定的分隔符模式,Scanner 将使用匹配空白字符的默认模式。
正如您所问的,blocked 意味着该方法等待并且直到所述事件发生才返回。
考虑一下:
System.out.println("Before");
someBlockingMethod();
System.out.println("After");
有
public void someBlockingMethod() {
// Sleep for a second (ignoring exceptions for simplicity)
Thread.sleep(1000);
}
您只会在someBlockingMethod() 返回后看到After,并且只有在所述事件发生后才会发生这种情况。因此方法阻塞。在示例中,该方法会阻塞一秒钟。
【讨论】:
hasNext true 但 next 阻塞的场景,因为您总是至少输入 使用控制台时输入信号结束(按enter时换行)被Scanner视为空白字符 .
Scanner 连接到一个尚未完全可用的资源,例如Stream。如果 Stream 传递符号 Hell 但还不是 分隔符,如 空格 或 行尾/流,那么你不需要不想将其用作令牌,因为一秒钟后o<whitespace> 来了。你想捕捉Hello 而不是Hell 和o。在这种情况下,hasNext 返回true,但next 将阻塞并等待o<whitespace> 到来。
Scanner#next 在到达 Scanner 使用的分隔符(空白是默认分隔符)或到达输入流的末尾之前不会返回字符串。
如果hasNext返回true,则表示输入流中肯定还有更多数据,但可能仍需要阻塞,直到到达分隔符/EOF。
【讨论】:
如果你调试下面的代码,你会发现,实际上是 hasNext() 方法阻塞并等待用户输入:
Scanner scanner = new Scanner(System.in);
if (scanner.hasNext()) {
String s = scanner.next();
}
那是因为 hasNext() 内部有一个阻塞步骤:
public boolean hasNext() {
ensureOpen();
saveState();
while (!sourceClosed) {
if (hasTokenInBuffer())
return revertState(true);
readInput(); //THIS IS WAITING FOR USER INPUT
}
...
在控制台输入的情况下,hasNext() 等到输入完整的令牌并返回 true,然后后续的 next() 调用不会阻塞。
在非控制台输入的情况下,即使没有完整的token,hasNext()也会返回true,后续的next()调用会阻塞并等待完整的token。
【讨论】: