1. 引言

使用Java的Scanner类读取System.in输入时,IDE常会提示资源泄漏警告。**若未显式关闭Scanner*,可能会看到类似“Resource leak: 'scanner' is never closed*”的警告。但关闭与System.in绑定的Scanner需谨慎处理,否则可能引发意外问题。

本文将探讨关闭Scanner的重要性及正确操作方式。

2. 理解警告机制

Java中,文件、网络连接、输入流等资源使用后应关闭以释放系统内存。Scanner类实现了Closeable接口,用于读取原始值和字符串(包括文件和System.in),其持有的资源需在不再使用时释放。

主流IDE(如Eclipse、VS Code)在未正确关闭Scanner时会显示警告:

资源泄漏警告

3. 使用close()方法关闭Scanner

通过close()方法可释放Scanner占用的系统资源,尤其当读取文件或System.in时。最佳实践是在finally块中关闭,确保异常发生时资源仍能正确释放:

@Test
void givenUserName_whenGetGreetingMessage_thenReturnsWelcomeMessage() {
    String input = "Anees\n";
    ByteArrayInputStream inputStream = new ByteArrayInputStream(input.getBytes());
    Scanner scanner = new Scanner(inputStream);

    ScannerClose example = new ScannerClose();
    String result = example.getGreetingMessage(scanner);

    assertEquals("Hi, Anees Welcome to Baeldung", result);
    scanner.close();
}

⚠️ 踩坑预警:关闭与System.in绑定的Scanner会引发问题。System.in代表标准输入流(通常是键盘),关闭后程序将无法读取用户输入,且在同一程序中无法重新打开。

若创建多个System.inScanner实例,关闭任一实例都会导致整个程序的输入流关闭。再次读取输入时将抛出异常:

Scanner scanner = new Scanner(System.in);

System.out.print("Enter your name: ");
String name = scanner.nextLine();
System.out.println("Hi, " + name + " Welcome to Baeldung!");

scanner.close();

System.out.print("Enter your age: ");
int age = scanner.nextInt();

System.out.println("Your age is: " + age);

执行结果:

Enter your name: Anees
Hi, Anees Welcome to Baeldung!
Enter your age: Exception in thread "main" java.lang.IllegalStateException: Scanner closed
    at java.base/java.util.Scanner.ensureOpen(Scanner.java:1150)
    at java.base/java.util.Scanner.next(Scanner.java:1573)
    at java.base/java.util.Scanner.nextInt(Scanner.java:2258)
    at java.base/java.util.Scanner.nextInt(Scanner.java:2212)

正确实践

  • System.in使用单一Scanner实例
  • 避免关闭,或仅在不再需要输入时关闭

4. 使用try-with-resources关闭Scanner

通过try-with-resources可在代码块结束时自动关闭Scanner,即使发生异常也能确保资源释放。无需finally块,降低资源泄漏风险:

@Test
void givenUserName_whenGetGreetingMessage_thenReturnsWelcomeMessage() {
    String input = "Anees\n";
    ByteArrayInputStream inputStream = new ByteArrayInputStream(input.getBytes());

    String result;
    try (Scanner scanner = new Scanner(inputStream)) {
        ScannerTryWithResources example = new ScannerTryWithResources();
        result = example.getGreetingMessage(scanner);
    }

    assertEquals("Hi, Anees Welcome to Baeldung", result);
}

try块执行完毕后,Java自动关闭Scanner实例,使代码更简洁可靠。**强烈推荐使用try-with-resources**,它确保资源清理的可靠性。

5. 总结

本文探讨了关闭Scanner的重要性及正确方法。良好的资源管理可防止泄漏,保障程序稳定运行。

关键要点

  • 读取文件时必须关闭Scanner
  • 处理System.in需格外谨慎:使用单一实例,仅在不再需要输入时关闭
  • try-with-resources是资源管理的最佳实践,确保自动关闭且代码更健壮