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
相关产品推荐
相关产品推荐

