Scanner.hasNextLine()
状态的javadoc:
如果此扫描仪的输入中有另一行,则返回true。 在等待输入时,此方法 可能 会阻止。扫描仪 不要超越任何输入。
该方法会在什么条件下阻止?
答案 0 :(得分:20)
这取决于扫描仪从中获取输入的来源。
例如,如果它是一个文件,那么整个输入都是可用的,因此hasNextLine()
不会阻止(因为它可以确定地知道何时到达文件末尾并且#&# 39;不再输入。
另一方面,如果源是标准输入,则总会有更多输入 - 用户总是可以输入更多输入 - 因此hasNextLine()
会阻塞,直到用户键入新的输入行。< / p>
答案 1 :(得分:4)
如何判断它是否会阻止?
为了确定hasNextLine
是否会阻止,遗憾的是不支持用例。
这是因为底层资源并不总是提供用于在流中窥视的API。换句话说,hasNextLine
的实现会调用本身可能阻塞的方法,因此问题是固有的。
那么,该怎么办?
如果这确实是一个必需的用例,我建议采用以下方法之一:
确保条件适合hasNextLine
。仅向扫描仪提供具有明确结束的源(例如文件或字符串),而不是“开放式”#34;输入,例如System.in
。
如果这是API的一部分,您可以将扫描仪包装在您自己的类中,只显示&#34; safe&#34;构造
从头开始使用willHasNextLineBlock
类型的方法滚动自己的类。这可能可能使用InputStream.available稍微强有力地实现。
在超级丑陋的解决方法类别下,我们发现:
尝试在单独的线程中调用hasNextLine
并查看它是否在合理的时间内返回,如下所示:
boolean wouldBlock = false;
Thread t = new Thread(() -> s.hasNextLine());
t.start();
try {
t.join(100);
} catch (InterruptedException e) {
wouldBlock = true;
}
使用自定义输入流(某些,如peekable stream,可以在调用hasNextLine
之前点击。{类似于此
CustomStream wrapped = new CustomStream(originalSource)
Scanner s = new Scanner(wrapped);
...
if (wrapped.hasNextLine())
// s.hasNextLine would not block
else
// s.hasNextLine would block
(但请注意,这有点不安全,因为扫描仪可能已缓存CustomStream
中的一些数据。)
答案 2 :(得分:2)
假设“决定它是否会阻止”你的意思是你想知道什么时候会出现这种情况。
查看hasNextLine
方法
String result = findWithinHorizon(linePattern(), 0);
现在,看一下findWithinHorizon
方法
public String findWithinHorizon(Pattern pattern, int horizon) {
ensureOpen();
if (pattern == null)
throw new NullPointerException();
if (horizon < 0)
throw new IllegalArgumentException("horizon < 0");
clearCaches();
// Search for the pattern
while (true) { //it may block here if it never break
String token = findPatternInBuffer(pattern, horizon);
if (token != null) {
matchValid = true;
return token;
}
if (needInput)
readInput();
else
break; // up to end of input
}
return null;
}
正如您所看到的,它会无限循环,直到达到结束,或者直到它成功读取。
findPatternInBuffer
是Scanner
类的私有方法,尝试读取输入。
private String findPatternInBuffer(Pattern pattern, int horizon) {
matchValid = false;
matcher.usePattern(pattern);
int bufferLimit = buf.limit();
int horizonLimit = -1;
int searchLimit = bufferLimit;
if (horizon > 0) {
horizonLimit = position + horizon;
if (horizonLimit < bufferLimit)
searchLimit = horizonLimit;
}
matcher.region(position, searchLimit);
if (matcher.find()) {
if (matcher.hitEnd() && (!sourceClosed)) {
// The match may be longer if didn't hit horizon or real end
if (searchLimit != horizonLimit) {
// Hit an artificial end; try to extend the match
needInput = true;
return null;
}
// The match could go away depending on what is next
if ((searchLimit == horizonLimit) && matcher.requireEnd()) {
// Rare case: we hit the end of input and it happens
// that it is at the horizon and the end of input is
// required for the match.
needInput = true;
return null;
}
}
// Did not hit end, or hit real end, or hit horizon
position = matcher.end();
return matcher.group();
}
if (sourceClosed)
return null;
// If there is no specified horizon, or if we have not searched
// to the specified horizon yet, get more input
if ((horizon == 0) || (searchLimit != horizonLimit))
needInput = true;
return null;
}
我发布了整个方法,让您更好地了解“成功阅读”的含义。