在Java的输入流处理场景中,Scanner作为常用的输入解析工具,经常和System.in标准输入流配合使用。很多开发者在处理完输入操作后,会对相关资源进行关闭操作,但其中存在不少容易踩坑的误区,处理不当会引发程序异常或者资源泄漏问题。

常见的资源关闭误区
误区一:关闭Scanner时同时关闭System.in
不少开发者认为Scanner是包装了System.in的流,关闭Scanner就应该同时关闭底层的System.in,于是写出如下代码:
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入内容:");
String input = scanner.nextLine();
System.out.println("你输入的内容是:" + input);
// 错误操作:关闭Scanner的同时会关闭System.in
scanner.close();
// 后续再次尝试使用System.in读取输入
Scanner newScanner = new Scanner(System.in);
System.out.println("请再次输入内容:");
String newInput = newScanner.nextLine();
System.out.println("第二次输入的内容是:" + newInput);
}
}
执行上述代码后,第二次输入时会直接抛出异常,因为System.in是标准输入流,属于JVM级别的全局资源,一旦被关闭,后续所有基于System.in的操作都会失效,无法再读取控制台输入。
误区二:忘记关闭Scanner导致资源泄漏
如果Scanner包装的是文件流、网络流等需要手动释放的资源,忘记关闭Scanner会导致底层资源无法被回收,引发资源泄漏。但很多开发者因为System.in的特殊性,就认为所有Scanner都不需要关闭,这也是不正确的认知。
误区三:重复关闭Scanner
部分开发者会在代码中多次调用scanner.close()方法,虽然重复关闭不会引发异常,但属于冗余操作,不符合代码规范,也可能在复杂逻辑中引发不可预期的问题。
不同场景下的关闭最佳实践
场景一:Scanner仅包装System.in
当Scanner的唯一作用是读取控制台输入,底层流只有System.in时,不需要手动关闭Scanner。因为System.in是JVM管理的标准输入流,程序运行期间会一直存在,程序结束后JVM会自动回收相关资源,手动关闭反而会导致后续输入操作失效。
如果确实需要在代码中显式关闭资源,正确的做法是只关闭Scanner,不关闭System.in,但需要注意关闭后不能再使用System.in。如果后续还有输入需求,就不要执行关闭操作。
场景二:Scanner包装其他可关闭流
当Scanner包装的是FileInputStream、Socket流等需要手动释放的资源时,必须关闭Scanner,因为关闭Scanner会自动关闭底层的包装流,释放系统资源。此时推荐使用try-with-resources语法,避免忘记关闭资源:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class FileScannerTest {
public static void main(String[] args) {
// 使用try-with-resources自动关闭资源
try (FileInputStream fis = new FileInputStream("test.txt");
Scanner scanner = new Scanner(fis)) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
// 离开try代码块后,scanner和fis会自动关闭,无需手动调用close方法
}
}
上述代码中,try-with-resources会在代码块执行结束后自动调用资源的close方法,即使发生异常也会正常释放资源,避免了手动关闭的遗漏问题。
核心注意事项总结
- System.in是全局标准输入流,不要通过scanner.close()关闭它,除非确定后续不再使用任何基于System.in的输入操作。
- 仅包装System.in的Scanner可以不关闭,程序结束后JVM会自动处理相关资源,关闭反而可能引发问题。
- 包装文件流、网络流等资源的Scanner必须关闭,优先使用try-with-resources语法简化关闭逻辑。
- 不要在代码中重复调用scanner.close()方法,避免冗余操作和潜在风险。
正确区分不同场景下的资源关闭逻辑,才能既避免资源泄漏,又不会引发不必要的程序异常,让输入流处理代码更加健壮。