Java 使用带有 try-with-resources 的扫描仪

Java using scanner with try-with-resources

我有两个版本的 Java 代码获取用户输入直到用户输入 "q" 版本 1:

public class Test {
    public static void main(String[] args) {
        String input = "";
        while (!input.equals("q")) {
            Scanner scanner = new Scanner(System.in);
            System.out.print("Input: ");
            input = scanner.nextLine();
            System.out.println("Input was: " + input);
        }
    }
}

版本 2:

public class Test {
    public static void main(String[] args) {
        String input = "";
        while (!input.equals("q")) {
            try(Scanner scanner = new Scanner(System.in)){
                System.out.print("Input: ");
                input = scanner.nextLine();
                System.out.println("Input was: " + input);
            }
        }
    }
}

版本 1 按预期工作,但版本 2 不按预期工作。 即在第一次读取用户输入后,会产生错误

Input: 12
Input was: 12Exception in thread "main" 
Input: java.util.NoSuchElementException: No line found
    at java.util.Scanner.nextLine(Scanner.java:1540)
    at RealEstateCompany.main(RealEstateCompany.java:115)

我的猜测是因为版本 2 使用 try with resource 所以它在使用后关闭扫描器并导致错误?

提前感谢您的帮助!

[更新] 版本 3:

public class Test {
    public static void main(String[] args) {
        String input = "";
        try(Scanner scanner = new Scanner(System.in)){
            while (!input.equals("q")) {
                System.out.print("Input: ");
                input = scanner.nextLine();
                System.out.println("Input was: " + input);
            }
        }
    }
}

版本 3 有效。但是,为什么版本3可以,版本2不行呢?

试试这个:

   String input = "";
   try (Scanner scanner = new Scanner(System.in)) {
       while (!input.equals("q")) {
           System.out.print("Input: ");
           input = scanner.nextLine();
           System.out.println("Input was: " + input);
       }
   }

您可以在 try-with-resources 中使用每个实现 CloseableAutoCloseable 的 class,当代码到达 try 调用的末尾时,它会调用 close() 函数 Scanner class 在我们的例子中。

为我的评论添加更多细节

一个try-with块定义如下:

try(...) {
   ...
}

其中括号中的参数需要是java.lang.AutoCloseable. An example is the class java.io.InputStream的实例,这也是System.in的class。

A try-with 尝试在块离开后自动关闭其提供的资源。根据使用的资源,它还会关闭所有自己的子资源。

以您的示例为例,您有 try(Scanner scanner = new Scanner(System.in)),它使用 Scanner 作为资源。扫描仪本身使用 System.in 作为资源。一旦离开 try 块(到达 } 时),它就会尝试关闭其资源,即 Scanner 实例。此实例还尝试关闭 资源,即 System.in.

一旦 System.in 关闭,您将无法再从控制台获得任何输入(我认为至少需要一些额外的工作...)。

具体来说,在你的第二个例子中:

while (!input.equals("q")) {
    try(Scanner scanner = new Scanner(System.in)){
            ...
    }  // <--- The block is left, scanner is closed, System.in is closed
} // <-- start a new iteration

这里仅经过一次迭代,System.in 就关闭了。当然,您在下一次迭代中创建了一个新的 Scanner,但是 System.in 保持关闭状态 ,这就是为什么在这种情况下会出现异常。

你的第三个例子:

try(Scanner scanner = new Scanner(System.in)){
    while (!input.equals("q")) {
        ...
    } // <-- start a new iteration, while still in the same try block
} // <-- only after the while, your resources are closed

在这里你正在循环 while,而 仍在里面 try。因此,在您离开 whiletry 之前,不会关闭任何资源。这意味着 ScannerSystem.in 保持不变。这允许您继续从控制台读取,直到您完成循环。

我 运行 一些测试并将 catch 块添加到您的 code.here 的代码中

public static void main(String[] args) {
    String input = "";
    while (!input.equals("q")) {
        try(Scanner scanner = new Scanner(System.in)){
            System.out.print("Input: ");
            input = scanner.nextLine();
            System.out.println("Input was: " + input);
        }
        catch (Exception e) {
            e.printStackTrace();
        }            
    }
}

添加catch块时,有两种结果 1,仅输入 q,按预期工作 2,输入任何其他字符串,异常

Input: java.util.NoSuchElementException: No line found
at java.util.Scanner.nextLine(Scanner.java:1585)
at rews.pub.Test.main(Test.java:11)

添加 catch 块后,我们会看到程序不会停止,因为 while 循环

这是另一个更简单的测试

public class Test {
public static void main(String[] args) {
    String input = "";
    Scanner scanner = new Scanner(System.in);
    System.out.println("inout--1---");
    input = scanner.nextLine();
    scanner.close();

    Scanner scanner2 = new Scanner(System.in);
    System.out.println("inout--2---");
    input = scanner2.nextLine();
    scanner2.close();

}

}

同样的异常

inout--1---
11
inout--2---
Exception in thread "main" java.util.NoSuchElementException: No line  found
at java.util.Scanner.nextLine(Scanner.java:1585)
at rews.pub.Test.main(Test.java:15)

这是我的看法。 在第一个 运行 的末尾,try() 块将关闭块中的资源,意味着我们关闭 system.in system.in是inputSteam的一个对象,而system.in是final静态的,不能像'new Scanner(System.in)'

一样再次打开