Java System.in hasNext 方法仅在第一次调用时有效
Java System.in hasNext method works only first time it is called
这个问题难倒我了。我写了一个从循环内部调用的方法。第一次完美运行,之后就挂了。
这是方法:
public static String promptUser(){
String path = "";
Scanner reader = new Scanner(System.in);
while (!path.contains(ROOT_FOLDER)){
System.out.println(String.format("Please paste in the directory path from WinSCP, including %s: ", ROOT_FOLDER));
while (true) {
if (reader.hasNext()){
path = reader.nextLine();
break;
}
}
}
reader.close();
return path;
}
这就是循环
while (true) {
try {
listFiles(promptUser());
break;
}
catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
}
}
我第一次 运行 它会多次提示用户获取我们需要的信息(目录路径)。然后它向 FTP 服务器发送请求,如果该路径不存在,我希望它继续提示用户。但是我的调试器告诉我在第二轮它只是挂起:
if (reader.hasNext()){
再多的回车键也无法继续。在第一次调用 promptUser 时,我可以输入没有根文件夹的内容,它会一直询问,直到它获得根文件夹。那么为什么它在第二次调用时不这样做呢?
这是怎么回事?
获取下一个元素时,不应在循环内使用 break
。这会导致您的 while(true)
循环退出。这意味着您获得第一个项目并完成。
你应该把它改成这样:
while(reader.hasNext()) {
path = reader.nextLine();
// do something with the path here...
}
阅读 hasNext()
的文档
Returns 如果此扫描器在其输入中有另一个标记,则为真。此方法可能会在等待输入扫描时阻塞。扫描仪不会前进超过任何输入。
Returns:
当且仅当此扫描器有另一个令牌时才为真
所以,hasNext() 正在等待您输入一些值。它会等到找到用户输入的单个字符串。
第一次调用 promptUser
时,它会执行以下操作:
- 创建一个
Scanner
包装 System.in
。
- 调用 hashNext,它会阻塞直到有数据要读取。
- 读取一行。
- 关闭
Scanner
.
- Return行。
问题出在第 4 步。当您关闭 Scanner
时,您 也会 关闭 System.in
。
下次你打电话给 promptUser
- 创建另一个包裹
System.in
的 Scanner
。 System.in
此时关闭。
- 立即调用
hashNext()
returns false
... 因为 Scanner
包裹的流已关闭。
- 重复 2. 令人作呕。你有一个无限循环。
解决方案:不要关闭 System.in
或包裹它的 Scanner
。并且不要只创建第二个 Scanner
来包装 System.in
。相反,重复使用原来的 Scanner
。
But is it necessary to close the scanner at some point?
您永远不需要关闭包装(原始)System.in
流的 Scanner
。我们关闭流的原因是:
- 导致写入缓冲数据(对于输出流),并且
- 避免文件描述符泄漏。
泄漏文件描述符的问题是进程(即您的 JVM)一次只能打开一定数量的文件。如果您泄漏文件描述符,您可能会发现尝试打开文件开始失败并出现意外 IOException
s。
在System.in
的情况下没有要写入的数据。因为你不能再打开System.in
(因为你不知道它连接的是什么)最多一个文件描述符可以是"leaked",所以这不是问题。
Eclipse warns that I should.
关于关闭扫描器等的 Eclipse 启发式方法相当简单。在这种情况下,警告是 可能 误报,但我需要查看代码才能确定。
这个问题难倒我了。我写了一个从循环内部调用的方法。第一次完美运行,之后就挂了。
这是方法:
public static String promptUser(){
String path = "";
Scanner reader = new Scanner(System.in);
while (!path.contains(ROOT_FOLDER)){
System.out.println(String.format("Please paste in the directory path from WinSCP, including %s: ", ROOT_FOLDER));
while (true) {
if (reader.hasNext()){
path = reader.nextLine();
break;
}
}
}
reader.close();
return path;
}
这就是循环
while (true) {
try {
listFiles(promptUser());
break;
}
catch (Exception e) {
e.printStackTrace();
System.err.println(e.getMessage());
}
}
我第一次 运行 它会多次提示用户获取我们需要的信息(目录路径)。然后它向 FTP 服务器发送请求,如果该路径不存在,我希望它继续提示用户。但是我的调试器告诉我在第二轮它只是挂起:
if (reader.hasNext()){
再多的回车键也无法继续。在第一次调用 promptUser 时,我可以输入没有根文件夹的内容,它会一直询问,直到它获得根文件夹。那么为什么它在第二次调用时不这样做呢?
这是怎么回事?
获取下一个元素时,不应在循环内使用 break
。这会导致您的 while(true)
循环退出。这意味着您获得第一个项目并完成。
你应该把它改成这样:
while(reader.hasNext()) {
path = reader.nextLine();
// do something with the path here...
}
阅读 hasNext()
Returns 如果此扫描器在其输入中有另一个标记,则为真。此方法可能会在等待输入扫描时阻塞。扫描仪不会前进超过任何输入。 Returns: 当且仅当此扫描器有另一个令牌时才为真
所以,hasNext() 正在等待您输入一些值。它会等到找到用户输入的单个字符串。
第一次调用 promptUser
时,它会执行以下操作:
- 创建一个
Scanner
包装System.in
。 - 调用 hashNext,它会阻塞直到有数据要读取。
- 读取一行。
- 关闭
Scanner
. - Return行。
问题出在第 4 步。当您关闭 Scanner
时,您 也会 关闭 System.in
。
下次你打电话给 promptUser
- 创建另一个包裹
System.in
的Scanner
。System.in
此时关闭。 - 立即调用
hashNext()
returnsfalse
... 因为Scanner
包裹的流已关闭。 - 重复 2. 令人作呕。你有一个无限循环。
解决方案:不要关闭 System.in
或包裹它的 Scanner
。并且不要只创建第二个 Scanner
来包装 System.in
。相反,重复使用原来的 Scanner
。
But is it necessary to close the scanner at some point?
您永远不需要关闭包装(原始)System.in
流的 Scanner
。我们关闭流的原因是:
- 导致写入缓冲数据(对于输出流),并且
- 避免文件描述符泄漏。
泄漏文件描述符的问题是进程(即您的 JVM)一次只能打开一定数量的文件。如果您泄漏文件描述符,您可能会发现尝试打开文件开始失败并出现意外 IOException
s。
在System.in
的情况下没有要写入的数据。因为你不能再打开System.in
(因为你不知道它连接的是什么)最多一个文件描述符可以是"leaked",所以这不是问题。
Eclipse warns that I should.
关于关闭扫描器等的 Eclipse 启发式方法相当简单。在这种情况下,警告是 可能 误报,但我需要查看代码才能确定。