You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java重定向System.in执行多测试用例时出现空输入流异常如何解决?

问题根因

你Main类中使用的scanner是静态全局实例,它仅会在Main类加载时初始化一次,绑定当时的System.in对象。后续测试中你调用System.setIn更换了输入流,已经初始化完成的Scanner并不会感知到System.in的变更,依然会从已经被读完的旧输入流中读取数据,自然就会抛出输入流为空的NoSuchElementException。

修复方案

方案1:调整业务代码(推荐)

不要复用静态Scanner实例,每次调用in()方法时新建Scanner,绑定当前最新的System.in:

public static int in(String message, int from, int to) {
    if (message != null && !message.isEmpty()) {
        System.out.print(message);
    }
    // 每次调用都新建Scanner实例
    Scanner scanner = new Scanner(System.in);
    try {
        String input = scanner.next();
        // 原有校验逻辑保持不变
    } catch (NoSuchElementException e) {
        throw new NoSuchElementException("\n\nArguments input incomplete.");
    }
}

如果不想每次调用in()都新建Scanner,也可以在Main类新增重置Scanner的静态方法,测试每次执行前调用:

// Main类新增方法
public static void resetScanner() {
    scanner = new Scanner(System.in);
}

// 测试类的set方法末尾补充调用
private static void set(int... args) {
    // 原有重定向System.in、System.out的逻辑不变
    Main.resetScanner();
}

方案2:仅调整测试代码(不修改业务逻辑)

如果不能修改业务代码,可以通过反射在每次测试前重置Main类的静态Scanner字段:

private static void set(int... args) throws Exception {
    // 原有重定向System.in、System.out的逻辑不变
    // 反射重置Scanner
    Field scannerField = Main.class.getDeclaredField("scanner");
    scannerField.setAccessible(true);
    scannerField.set(null, new Scanner(System.in));
}

额外优化建议

每次测试结束后记得将System.in和System.out恢复为原始默认值,避免影响其他测试用例的执行:

// 测试类新增变量存储原始流
private static final InputStream originalIn = System.in;
private static final PrintStream originalOut = System.out;

// 每个测试用例执行后恢复流
@AfterEach
void restoreSystemIO() {
    System.setIn(originalIn);
    System.setOut(originalOut);
}

内容的提问来源于stack exchange,提问作者metamorphogenesis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 21:06:04