Java关闭Scanner触发NoSuchElementException及内存泄漏问题求解
Java多类循环调用Scanner输入关闭报错问题解决方案
问题根因
- 当你调用
Scanner.close()方法时,该操作不仅会回收Scanner实例本身,还会同步关闭其绑定的底层输入流,你这里绑定的是全局的System.in标准输入流,一旦关闭后整个JVM进程生命周期内都无法再次打开,后续再新建Scanner读取输入就会抛出java.util.NoSuchElementException: No line found异常。 - 你担心的内存泄漏问题完全不需要顾虑:方法内创建的Scanner是局部变量,方法执行完成后就会被JVM垃圾回收器自动回收,不会长期占用内存;而
System.in是JVM内置全局流,程序退出时会自动释放,不存在泄漏风险。
最优优化方案
建议全局复用同一个Scanner实例,避免重复创建对象,也避免流关闭冲突,修改逻辑如下:
- 在抽象父类
Employee中定义静态全局Scanner,所有子类共用:
import java.util.Scanner; abstract public class Employee{ // 全局共用的Scanner实例,整个程序生命周期只创建一次 public static final Scanner SCAN = new Scanner(System.in); public Employee(){} String name, surname, rank; int salary = 0, daysoff = 20; public Employee(String name, String surname, String rank, int salary, int daysoff){ this.name = name; this.surname = surname; this.salary = salary; this.rank = rank; this.daysoff= daysoff; } // 程序所有输入逻辑执行完成后,调用该方法关闭流 public static void closeScan(){ SCAN.close(); } }
- 所有子类的
input_variables方法直接使用父类的静态Scanner,不需要重复创建:
// 以Guard类为例,ITPersonal类同理修改 public void input_variables(){ System.out.println("First name: "); this.name = Employee.SCAN.nextLine(); System.out.println("Last name: "); this.surname = Employee.SCAN.nextLine(); System.out.println("Night shifts (per month): "); this.night_shifts = Employee.SCAN.nextInt(); System.out.println("Late shifts (per month): "); this.late_shifts = Employee.SCAN.nextInt(); System.out.println("Early shifts (per month): "); this.early_shifts = Employee.SCAN.nextInt(); // nextInt()会残留换行符,要消费掉避免后续nextLine读空 Employee.SCAN.nextLine(); System.out.printf("Added %s, %s to company!", this.surname, this.name); }
- main方法所有输入逻辑执行完成后,再统一关闭Scanner:
public static void main(String args[]){ Employee new_guard[] = new Guard[5]; Employee new_it[] = new ITPersonal[5]; Employee new_manager[] = new Management[5]; int count_guard = 0, count_it = 0, count_manager = 0; for(int i = 0; i <= 14; i++){ if(i % 3 == 0){ new_guard[count_guard] = new Guard(); new_guard[count_guard].input_variables(); count_guard++; System.out.println(); }else if(i % 2 == 0){ new_it[count_it] = new ITPersonal(); new_it[count_it].input_variables(); count_it++; System.out.println(); }else{ new_manager[count_manager] = new Management(); new_manager[count_manager].input_variables(); count_manager++; System.out.println(); } } // 所有输入完成后统一关闭流 Employee.closeScan(); int k = 0, j = 0, l = 0; for(int i = 0; i < 15; i++){ if(i % 3 == 0){ System.out.println(new_manager[k].toString()); k++; }else if(i % 2 == 0){ System.out.println(new_it[j].toString()); j++; }else{ System.out.println(new_guard[l].toString()); l++; } } }
其他代码问题修正
- 字符串相等判断不要用
==,要用equals()方法,比如if("Senior Developer".equals(this.rank)),否则会出现判断失效的问题 - 注意变量名拼写统一:你的代码里同时出现了
rang和rank、bonusdays和bonusDays、bonusTage等拼写不一致的问题,会导致编译报错 - 调用
nextInt()后必须手动消费残留的换行符,否则下一次调用nextLine()会直接读取到空字符串,出现输入错位的问题
内容的提问来源于stack exchange,提问作者r3k0j
相关产品推荐
相关产品推荐

