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

Java单元测试预定义用户输入:多Scanner实例输入流失效问题

问题原因与解决方案:多Scanner实例复用输入流失败

核心原因

问题出在**Scanner.close()方法会连带关闭其关联的底层输入流**。你在main方法中关闭第一个Scanner时,把通过System.setIn()设置的ByteArrayInputStream也一并关闭了。而System.in是全局唯一的输入流,一旦被关闭,后续任何尝试读取它的操作都会直接抛出NoSuchElementException,因为输入源已经不存在了。


解决方案

方案1:复用同一个Scanner实例(推荐)

不要在每个方法中新建Scanner,而是将Scanner作为参数传递,或者使用全局实例(单元测试场景下全局实例无资源泄漏风险)。修改后的代码示例:

import java.io.ByteArrayInputStream;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        String data = "1\nThis is the first input\nThis is the second input";

        ByteArrayInputStream is = new ByteArrayInputStream(data.getBytes());
        System.setIn(is);
        
        Scanner scanner = new Scanner(System.in);
        System.out.println(scanner.nextLine());

        // 传递Scanner实例实现复用
        func(scanner);
        
        // 所有读取操作完成后统一关闭
        scanner.close();
    }

    private static void func(Scanner scanner) {
        System.out.println("First input: " + scanner.nextLine());
        System.out.println("Second input: " + scanner.nextLine());
    }
}

方案2:不关闭Scanner(单元测试场景适用)

如果无法传递Scanner实例,可以选择不关闭任何Scanner。单元测试中你设置的是自定义字节流,程序结束后JVM会自动回收资源,不会造成泄漏。修改后的代码:

import java.io.ByteArrayInputStream;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        String data = "1\nThis is the first input\nThis is the second input";

        ByteArrayInputStream is = new ByteArrayInputStream(data.getBytes());
        System.setIn(is);
        
        Scanner scanner = new Scanner(System.in);
        System.out.println(scanner.nextLine());
        // 不关闭Scanner
        // scanner.close();

        func();
    }

    private static void func() {
        Scanner scanner = new Scanner(System.in);

        System.out.println("First input: " + scanner.nextLine());
        System.out.println("Second input: " + scanner.nextLine());
        // 同样不关闭
        // scanner.close();
    }
}

方案3:重新设置System.in(复杂场景备选)

如果项目结构过于复杂,无法复用或不关闭Scanner,可以在每次读取前重新设置System.in。注意需要重新生成输入流,因为之前的读取已经消耗了部分字节:

import java.io.ByteArrayInputStream;
import java.util.Scanner;

public class Main {
    private static final String INPUT_DATA = "1\nThis is the first input\nThis is the second input";

    public static void main(String[] args) {
        resetSystemIn();
        
        Scanner scanner = new Scanner(System.in);
        System.out.println(scanner.nextLine());
        scanner.close();

        resetSystemIn();
        func();
    }

    private static void resetSystemIn() {
        ByteArrayInputStream is = new ByteArrayInputStream(INPUT_DATA.getBytes());
        System.setIn(is);
    }

    private static void func() {
        Scanner scanner = new Scanner(System.in);

        System.out.println("First input: " + scanner.nextLine());
        System.out.println("Second input: " + scanner.nextLine());

        scanner.close();
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 00:35:12