在Java编程中,Scanner类是处理输入操作的重要工具,它提供了多种方法来读取不同类型的数据,由于Scanner内部会打开底层资源(如System.in、文件流等),如果使用后未正确关闭,可能会导致资源泄漏,影响程序的性能和稳定性,掌握Scanner的正确关闭方法至关重要,本文将详细介绍Scanner关闭的必要性、不同场景下的关闭方式、常见问题及最佳实践,帮助开发者编写更健壮的代码。

为什么必须关闭Scanner
Scanner类在创建时会关联一个可关闭的资源,例如通过new Scanner(System.in)关联标准输入流,或通过new Scanner(new File("test.txt"))关联文件流,这些资源通常由操作系统管理,数量有限,如果Scanner对象使用后未被关闭,底层资源会一直被占用,直到程序结束,在长时间运行的服务器应用或高频调用的方法中,资源泄漏可能导致系统资源耗尽,最终引发程序崩溃,未关闭的文件流会阻止其他进程访问该文件,影响系统的整体效率。
Scanner关闭的基本方法
Java提供了标准的资源关闭机制,即使用close()方法释放Scanner占用的资源,以下是关闭Scanner的基本语法:
Scanner scanner = new Scanner(System.in);
try {
// 使用Scanner读取输入
String input = scanner.nextLine();
System.out.println("输入内容: " + input);
} finally {
scanner.close(); // 确保Scanner被关闭
}
在上述代码中,finally块确保无论是否发生异常,Scanner都会被关闭,这是最基础的关闭方式,适用于简单的输入操作,需要注意的是,close()方法本身也会抛出IOException,因此在某些场景下需要进一步处理异常。
不同场景下的Scanner关闭策略
关联标准输入流(System.in)
当Scanner与System.in关联时,关闭Scanner会同时关闭标准输入流,由于System.in是全局资源,关闭后可能导致其他需要读取标准输入的代码(如其他线程或后续代码)抛出异常,在需要持续读取用户输入的应用(如交互式控制台程序)中,通常不建议关闭System.in,如果必须关闭,应确保后续代码不再依赖标准输入流。
关联文件流或其他可关闭资源
当Scanner通过new Scanner(File)或new Scanner(InputStream)创建时,关闭Scanner不会自动关闭底层文件流或输入流,需要手动关闭底层资源,否则可能导致文件句柄泄漏,正确的做法是使用try-with-resources语句,确保资源自动关闭:

try (Scanner scanner = new Scanner(new File("test.txt"))) {
while (scanner.hasNextLine()) {
System.out.println(scanner.nextLine());
}
} // Scanner和FileInputStream会自动关闭
try-with-resources是Java 7引入的特性,它会自动调用实现了AutoCloseable接口的资源对象的close()方法,无需手动编写finally块,从而简化代码并避免资源泄漏。
关联网络流或数据库连接
当Scanner与网络输入流(如Socket.getInputStream())或数据库结果集(如ResultSet的getCharacterStream())关联时,关闭Scanner不会自动关闭这些网络连接或数据库资源,必须确保底层连接被正确关闭,通常也需要使用try-with-resources或手动在finally块中关闭资源:
try (Scanner scanner = new Scanner(socket.getInputStream())) {
while (scanner.hasNext()) {
System.out.println(scanner.next());
}
} // Scanner和SocketInputStream会自动关闭
Scanner关闭的常见问题及解决方案
忘记关闭Scanner
这是最常见的问题,尤其是在简单的测试代码或示例程序中,开发者可能认为程序结束后资源会自动释放,但实际上JVM的垃圾回收机制不会主动调用close()方法,解决方案是养成使用try-with-resources的习惯,或确保在finally块中调用close()方法。
多次关闭Scanner
如果同一个Scanner对象被多次调用close()方法,第二次及之后的调用会抛出IllegalStateException,这是因为Scanner在关闭后会标记为已关闭状态,禁止再次使用,为避免此问题,可以在关闭前检查Scanner是否已关闭:
if (scanner != null && scanner.hasNext()) {
scanner.close();
}
关闭Scanner后继续使用
在调用close()方法后,继续使用Scanner的方法(如next()、hasNext()等)会抛出IllegalStateException,应在关闭前完成所有输入操作,或确保关闭后不再引用该Scanner对象。

最佳实践总结
- 优先使用try-with-resources:对于所有实现了
AutoCloseable接口的资源(包括Scanner),应优先使用try-with-resources语句,确保资源自动关闭。 - 避免关闭System.in:除非程序不再需要标准输入流,否则不要关闭与
System.in关联的Scanner。 - 确保底层资源关闭:当Scanner关联文件、网络流或数据库连接时,必须确保底层资源也被正确关闭。
- 异常处理:在手动关闭Scanner时,应捕获并处理可能抛出的
IOException,避免异常未处理导致程序中断。 - 代码可读性:在复杂的代码块中,使用
try-with-resources可以提高代码的可读性和维护性,减少资源泄漏的风险。
示例代码
以下是一个结合try-with-resources和异常处理的完整示例,展示如何安全地使用并关闭Scanner:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class ScannerExample {
public static void main(String[] args) {
File file = new File("example.txt");
try (Scanner scanner = new Scanner(file)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.err.println("文件未找到: " + e.getMessage());
}
}
}
在这个示例中,try-with-resources确保Scanner和FileInputStream在代码块执行完毕后自动关闭,即使发生异常也不会导致资源泄漏,通过捕获FileNotFoundException,程序能够优雅地处理文件不存在的情况。
正确关闭Scanner是Java编程中的一项基本技能,开发者应根据不同的使用场景选择合适的关闭策略,并遵循最佳实践,确保资源的有效管理和程序的稳定性,通过养成良好的编码习惯,可以避免因资源泄漏引发的各种问题,提高代码的质量和可靠性。

















