【问题标题】:Java System.in hasNext method works only first time it is calledJava System.in hasNext 方法仅在第一次调用时有效
【发布时间】:2016-04-20 10:05:04
【问题描述】:

这个问题把我难住了。我编写了一个从循环内部调用的方法。第一次完美运行,之后就挂了。

这是方法:

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 时,我可以在没有根文件夹的情况下输入一些内容,它会一直询问直到它获得根文件夹。那么为什么它不在第二次调用时这样做呢?

发生了什么事?

【问题讨论】:

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


    【解决方案1】:

    第一次调用 promptUser 时,它会执行以下操作:

    1. 创建一个包含System.inScanner
    2. 调用 hashNext 阻塞直到有数据要读取。
    3. 读取一行。
    4. 关闭Scanner
    5. 返回线路。

    问题出在第 4 步。当您关闭Scanner 时,您关闭了System.in

    下次你打电话给promptUser

    1. 创建另一个包裹System.inScannerSystem.in 此时已关闭。
    2. 调用hashNext() 会立即返回false ...因为Scanner 包裹的流已关闭。
    3. 重复 2. 令人作呕。你有一个无限循环。

    解决方案:不要关闭 System.in 或包裹它的 Scanner。不要只创建第二个 Scanner 来包装 System.in。而是重用原始的Scanner


    但是是否有必要在某个时候关闭扫描仪?

    您永远不需要关闭包装(原始)System.in 流的Scanner。我们关闭流的原因是:

    • 导致写入缓冲数据(用于输出流),并且
    • 避免文件描述符泄漏。

    文件描述符泄漏的问题在于,一个进程(即您的 JVM)一次只能打开一定数量的文件。如果您泄漏文件描述符,您可能会发现打开文件的尝试开始失败并出现意外的IOExceptions。

    System.in 的情况下,没有要写入的数据。由于你不能再次打开System.in(因为你不知道它连接的是什么)最多可以“泄露”一个文件描述符,所以这不是问题。

    Eclipse 警告我应该这样做。

    关于关闭扫描器等的 Eclipse 启发式方法相当简单。在这种情况下,警告可能是误报,但我需要查看代码才能确定。

    【讨论】:

    • 谢谢,这解决了我的问题,并且您对问题的解释比我在该主题上发现的其他问题要好得多。但是是否有必要在某个时候关闭扫描仪? Eclipse 警告我应该这样做。
    【解决方案2】:

    在获取下一个元素时,不应在循环内使用break。这会导致您的 while(true) 循环退出。这意味着您得到第一个项目并完成。

    你应该把它改成这样:

    while(reader.hasNext()) {
        path = reader.nextLine();
        // do something with the path here...
    }
    

    【讨论】:

    • 这是我尝试的第一件事,但它给了我一个不同的问题。它再次在第一次调用时正常工作,但在第二次调用时,它只会一遍又一遍地将消息打印到控制台,而无需等待任何输入。这就是为什么我将它包装在两个循环中,while(true) 循环是否存在并不重要,因为它位于另一个等待正确输入的循环中。我真的不明白为什么同一种方法似乎有两种不同的行为。
    【解决方案3】:

    阅读hasNext()的文档

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

    所以,hasNext() 正在等待你输入一些值。它会一直等到找到用户输入的单个字符串。

    【讨论】:

    • 第一次调用promptUser时会这样,但第二次,我可以整天按Return,但没有任何反应。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-10-02
    • 1970-01-01
    • 2013-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多