
在Java中,System.in 是一个字节流(InputStream),其底层资源(如文件句柄)是共享且不可重复打开的。虽然多次构造 new Scanner(System.in) 语法上合法,但每个 Scanner 实例会独立尝试从同一输入流中读取数据——而一旦前一个 Scanner 已消费了部分输入(例如调用 nextInt() 读走第一个整数),后续 Scanner 在初始化或首次调用扫描方法时,可能因流已关闭、缓冲区耗尽或内部状态不一致而立即失败,典型表现就是 NoSuchElementException。
根本原因在于:Scanner 并非简单“指向”System.in,而是对其进行了缓冲和状态管理。多个 Scanner 实例竞争同一输入源,破坏了读取的原子性和顺序性,尤其在重定向场景下(输入来自文件而非交互终端)更为敏感。
✅ 正确解法是全局复用单个 Scanner 实例,并通过方法参数显式传递:
import java.util.Scanner;
class Main {
// 将 Scanner 作为参数传入,避免重复创建
public static int read(Scanner input) {
int num2 = input.nextInt();
System.out.println(num2);
return num2;
}
public static void main(String[] args) {
// 在 main 中创建唯一 Scanner 实例
Scanner input = new Scanner(System.in);
int num1 = input.nextInt();
System.out.println(num1);
read(input); // 复用同一实例
input.close(); // 建议显式关闭,释放资源
}
}? 关键要点:
立即学习“Java免费学习笔记(深入)”;
- 不要在多个方法中各自 new Scanner(System.in) —— 这是绝大多数此类错误的根源;
- 始终将 Scanner 作为参数传递,确保所有读取操作共享同一缓冲区与游标位置;
- 在使用完毕后调用 scanner.close()(尤其在处理文件重定向时),防止资源泄漏(注意:关闭 Scanner 也会关闭其底层 System.in,但在标准输入重定向场景中通常无副作用;若需多次复用,可省略关闭,JVM 退出时自动释放);
- 若逻辑复杂,也可将 Scanner 声明为 static 字段(不推荐用于多线程环境),但参数传递更清晰、更易测试、更符合面向对象设计原则。
运行命令 java Main output.txt 后,程序将稳定输出:
1 2
完全符合预期,且无异常。










