Java 关闭 Scanner 的最佳实践
1、简介
当使用 Java 的 Scanner
类读取 System.in
(标准输入)输入时,部分 IDE 会提示可能存在资源泄漏。
例如,若未显式关闭 Scanner
,可能收到警告:“Resource leak: ‘scanner’ is never closed”。但关闭关联 System.in
的 Scanner
需谨慎处理,以避免意外问题。
本文将带你了解关闭 Scanner
的重要性及在 Java 中的正确操作方式。
2、理解 IDE 提示的异常
在 Java 中,使用文件、网络连接(Socket)和输入流等资源后应关闭资源以释放系统内存。Scanner
类从文件或 System.in
等源读取原始值和字符串输入,由于实现了 Closeable
接口,因此它持有的资源需要在不使用时及时释放。
部分 IDE(如 Eclipse 和 Visual Studio Code)若检测到未正确关闭 Scanner
对象,会显示如下资源泄漏警告:
3、通过 close() 方法关闭 Scanner
在 Java 中,可通过 close()
方法关闭 Scanner
以释放系统资源,这在读取文件或 System.in
时尤为重要。
建议在 finally
代码块中关闭 Scanner
,确保即使发生异常也能正确释放资源,避免泄漏:
@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.in
创建多个 Scanner
实例,关闭其中任意一个都会使整个程序的输入流终止,导致后续读取输入时抛出异常:
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);
上例中,当尝试读取 age
时,由于之前关闭了 Scanner
,导致抛出 IllegalStateException: Scanner closed
异常:
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)
为避免 Scanner
引发的问题,应为 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
需格外谨慎。使用单一 Scanner
实例并仅在无需输入时关闭,可避免问题发生。
try-with-resources
方式能自动确保资源关闭,简化管理流程,使代码更简洁可靠。
Ref:https://www.baeldung.com/java-scanner-close