
当使用命令行重定向(如 `java main output.txt`)时,若每个方法都新建 `scanner(system.in)` 实例,会导致后续读取抛出 `nosuchelementexception`;正确做法是复用同一个 `scanner` 对象并将其作为参数传递。
在 Java 中,System.in 是一个单向的输入流(InputStream),其内部状态(如读取位置)由关联的 Scanner 实例维护。每次执行 new Scanner(System.in) 都会创建一个独立的扫描器,但它们共享底层的同一输入流缓冲区。当第一个 Scanner 读取并消耗掉部分输入(如 nextInt() 读走 1 并换行符后),第二个 Scanner 在初始化时可能已错过流头,或因底层流不可重置而无法重新定位,最终在尝试读取下一个整数时触发 NoSuchElementException。
解决方法非常明确:避免重复构造 Scanner(System.in),而是将已创建的 Scanner 实例显式传入需要读取的方法中。这样所有方法操作的是同一扫描上下文,确保输入流按序、无遗漏地被消费。
以下是修正后的完整代码示例:
import java.util.Scanner;
class Main {
// 接收 Scanner 实例作为参数,复用同一输入源
public static int read(Scanner input) {
int num2 = input.nextInt(); // 继续读取 input.txt 中的第二行 "2"
System.out.println(num2);
return num2;
}
public static void main(String[] args) {
Scanner input = new Scanner(System.in); // 全局唯一 Scanner
int num1 = input.nextInt(); // 读取第一行 "1"
System.out.println(num1);
read(input); // 复用该 Scanner
input.close(); // 建议显式关闭,释放资源(尤其在生产环境中)
}
}✅ 关键要点总结:
立即学习“Java免费学习笔记(深入)”;
- System.in 不可重置、不可重复绑定多个活跃 Scanner;
- 所有输入逻辑应基于同一个 Scanner 实例,通过方法参数传递实现共享;
- 使用完毕后调用 scanner.close() 是良好实践(虽对 System.in 关闭无实际影响,但可避免静态分析警告,并养成资源管理习惯);
- 若需更灵活的输入管理(如多线程或多次解析),可考虑将输入预读为 List
或 Stream 后分发,而非依赖实时流读取。
该方案简洁、高效,完全兼容标准输入重定向场景,是命令行 Java 工具开发中的基础最佳实践。










