Java控制台应用中Scanner触发NoSuchElementException问题求助
问题分析与解决方案
问题根源
选择选项2时抛出NoSuchElementException的核心原因是:你在AppointmentsSorter.getSortedList()方法中关闭了绑定System.in的Scanner。System.in是全局唯一的标准输入流,一旦被关闭,后续所有依赖它的输入操作(比如主菜单循环里的sc.nextLine())都会因流已关闭、无元素可读而抛出异常。
解决方案
避免在子模块中关闭关联System.in的Scanner,统一使用一个全局Scanner实例贯穿整个控制台流程,仅在程序完全结束时关闭一次。具体修改如下:
1. 修改主菜单方法,传递全局Scanner
public void selectOption(int doctorID) { Scanner sc = new Scanner(System.in); String option; do { System.out.println("Chose one from the options(write only the number):"); System.out.println("1. Show all appointments for a doctor."); System.out.println("2. Sort all appointments for a doctor."); System.out.println("3. Group patients."); System.out.println("4. Exit."); option = sc.nextLine(); while (true) { if (option.equals("1")) { int newID = changeDoctorID(doctorID); showAllAppointments(newID); break; } else if (option.equals("2")) { int newID = changeDoctorID(doctorID); // 将全局Scanner传递给排序方法 sortAllAppointments(newID, sc); break; } else if (option.equals("3")) { groupPatients(doctorID); break; } else if (option.equals("4")) { break; } else { System.out.println("Invalid input! Write only the number:"); option = sc.nextLine(); } } } while (!option.equals("4")); // 仅在程序退出时关闭一次Scanner sc.close(); }
2. 修改排序类,移除内部Scanner创建与关闭
import java.util.*; public class AppointmentsSorter { private final String appointmentFileName; private final String doctorFileName; private final String patientFileName; private final int doctorID; public AppointmentsSorter(String appointmentFileName, String doctorFileName, String patientFileName, int doctorID) { this.appointmentFileName = appointmentFileName; this.doctorFileName = doctorFileName; this.patientFileName = patientFileName; this.doctorID = doctorID; } // 改为接收外部传入的Scanner,不再内部创建 public List<Appointment> getSortedList(Scanner sc) { String option = getSortingOption(sc); List<Appointment> sortedAppointmentList; if (option.equals("1")) { sortedAppointmentList = makeAppointmentListIncreasingOrDecreasingOrder(getSortedAppointmentListByPatientName(), sc); } else if (option.equals("2")) { sortedAppointmentList = makeAppointmentListIncreasingOrDecreasingOrder(getSortedAppointmentListByDateTime(), sc); } else { sortedAppointmentList = makeAppointmentListIncreasingOrDecreasingOrder(getSortedAppointmentListByPatientID(), sc); } // 移除sc.close(),避免关闭System.in return sortedAppointmentList; } // 其余方法保持不变,因为它们已经依赖传入的Scanner参数 private List<Appointment> getSortedAppointmentListByPatientName() { return new ArrayList<>(); // 实现逻辑 } private List<Appointment> getSortedAppointmentListByPatientID() { CSVReader reader = new CSVReader(); List<Appointment> allAppointmentsList = reader.readAppointmentList(this.appointmentFileName); List<Appointment> currentDoctorAppointmentsList = allAppointmentsList.stream() .filter(appointment -> appointment.getDoctorID() == this.doctorID).toList(); List<Appointment> sortedCurrentDoctorAppointmentsList = currentDoctorAppointmentsList.stream() .sorted(Comparator.comparing(Appointment::getPatientID)).toList(); return sortedCurrentDoctorAppointmentsList; } private List<Appointment> getSortedAppointmentListByDateTime() { CSVReader reader = new CSVReader(); List<Appointment> allAppointmentsList = reader.readAppointmentList(this.appointmentFileName); List<Appointment> currentDoctorAppointmentsList = allAppointmentsList.stream() .filter(appointment -> appointment.getDoctorID() == this.doctorID).toList(); Comparator<Appointment> compareByDateAndTime = Comparator.comparing(Appointment::getDate).thenComparing(Appointment::getTime); List<Appointment> sortedCurrentDoctorAppointmentsList = currentDoctorAppointmentsList.stream().sorted(compareByDateAndTime).toList(); return sortedCurrentDoctorAppointmentsList; } private List<Appointment> makeAppointmentListIncreasingOrDecreasingOrder(List<Appointment> appointmentList, Scanner sc) { System.out.println("Select order - increasing or decreasing: "); String order = sc.nextLine(); while (true) { if (order.equalsIgnoreCase("increasing")) { return appointmentList; } else if (order.equalsIgnoreCase("decreasing")) { List<Appointment> reversedAppointmentList = new ArrayList<>(appointmentList); Collections.reverse(reversedAppointmentList); return reversedAppointmentList; } else { System.out.println("Invalid order! Enter again(increasing or decreasing): "); order = sc.nextLine(); } } } private String getSortingOption(Scanner sc) { System.out.println("Sort appointments by(enter only the number): "); System.out.println("1. by patient name 2. by date 3. patient ID"); String option = sc.nextLine(); while (true) { if (option.equals("1") || option.equals("2") || option.equals("3")) { return option; } else { System.out.println("Invalid option! Enter again: "); option = sc.nextLine(); } } } private List<Patient> getPatientListFromAppointments() { CSVReader reader = new CSVReader(); List<Appointment> appointmentList = reader.readAppointmentList(this.appointmentFileName); List<Integer> patientIDList = appointmentList.stream().map(Appointment::getPatientID).toList(); List<Patient> patientList = reader.readPatientList(this.patientFileName); List<Patient> filteredPatientList = new ArrayList<>(); for (int patientID : patientIDList) { for (Patient patient : patientList) { if (patient.getPatientID() == patientID && !filteredPatientList.contains(patient)) { filteredPatientList.add(patient); } } } return filteredPatientList; } private String getPatientFullName(int patientId, List<Patient> patientList) { for (Patient patient : patientList) { if (patient.getPatientID() == patientId) { return patient.getFirstName() + "" + patient.getLastName(); } } return ""; } }
3. 修改sortAllAppointments方法,接收并传递Scanner
private void sortAllAppointments(int doctorID, Scanner sc) { AppointmentsSorter sorter = new AppointmentsSorter("appointments.csv", "doctors.csv", "patients.csv", doctorID); List<Appointment> sortedList = sorter.getSortedList(sc); // 后续处理排序结果的逻辑 }
关键说明
System.in是全局单例流,关闭后无法重新打开,任何尝试读取已关闭流的操作都会抛出NoSuchElementException。- 控制台程序中建议只创建一个Scanner实例,负责所有输入操作,仅在程序退出时关闭它。
内容的提问来源于stack exchange,提问作者Todor
相关产品推荐
相关产品推荐

