Java读取标准输入(非交互式)时出现诡异输入错误问题
排查Java标准输入读取的诡异错误及修复方案
我一眼就看到了几个会导致输入异常的问题,咱们一步步拆解并修复:
问题1:多个Scanner实例共享System.in流
你的代码里Student类和Marks类各自创建了Scanner实例来读取标准输入。当多个Scanner操作同一个System.in时,很容易出现流的状态混乱——比如其中一个Scanner的读取操作会打乱另一个的指针位置,甚至如果某个Scanner被关闭(哪怕是隐式触发的),整个System.in都会被关闭,后续读取直接抛出异常。
问题2:sc.next()无法读取带空格的名字
sc.next()只会读取到第一个空白字符(空格、换行、制表符等)就停止,如果用户输入的名字是Mary Smith这种带空格的,name只会拿到Mary,紧接着的sc.nextInt()会尝试读取Smith,这显然不是整数,直接触发InputMismatchException。
修复后的完整代码
import java.util.Scanner; class Student { private int rollno; private String name; // 共用一个Scanner实例,避免流冲突 private Scanner sc; // 构造方法传入全局的Scanner public Student(Scanner sc) { this.sc = sc; } public void getRollNo() { System.out.println("Enter name and roll no (name can include spaces):"); // 读取包含空格的完整名字 name = sc.nextLine(); // 校验并读取学号,确保输入是有效整数 while (!sc.hasNextInt()) { System.out.println("请输入有效的整数学号!"); sc.nextLine(); // 吃掉无效输入内容 } rollno = sc.nextInt(); sc.nextLine(); // 吃掉nextInt()留下的换行符,避免影响后续读取 } public void putRollNo() { System.out.println("Name=" + name); System.out.println("Regno=" + rollno); } } class Marks extends Student { protected int mark1, mark2, mark3; // 继承父类的Scanner实例 public Marks(Scanner sc) { super(sc); } public void getMarks() { System.out.println("Enter marks for three subjects:"); // 校验并读取三科成绩 while (!sc.hasNextInt()) { System.out.println("请输入有效的整数成绩!"); sc.nextLine(); } mark1 = sc.nextInt(); while (!sc.hasNextInt()) { System.out.println("请输入有效的整数成绩!"); sc.nextLine(); } mark2 = sc.nextInt(); while (!sc.hasNextInt()) { System.out.println("请输入有效的整数成绩!"); sc.nextLine(); } mark3 = sc.nextInt(); sc.nextLine(); } public void putMarks() { putRollNo(); System.out.println("Mark1=" + mark1); System.out.println("Mark2=" + mark2); System.out.println("Mark3=" + mark3); } } // 测试入口类 public class StudentTest { public static void main(String[] args) { // 全局只创建一个Scanner实例,传递给所有需要的类 Scanner sc = new Scanner(System.in); Marks studentMarks = new Marks(sc); studentMarks.getRollNo(); studentMarks.getMarks(); studentMarks.putMarks(); sc.close(); // 最后统一关闭Scanner } }
关键修复说明
- 单一Scanner实例:在
main方法中创建唯一的Scanner,通过构造方法传递给Student和Marks类,所有输入操作共用这一个实例,彻底避免流冲突问题。 - 用
nextLine()读取完整名字:可以处理包含空格的姓名输入,同时在nextInt()之后调用sc.nextLine()吃掉残留的换行符,防止下一次nextLine()直接读取空字符串。 - 输入校验逻辑:增加循环判断确保用户输入的学号和成绩都是有效整数,避免因非法输入导致的程序崩溃。
内容的提问来源于stack exchange,提问作者S4rt-H4K
相关产品推荐
相关产品推荐

