Java GUI打印按钮触发NullPointerException:无法调用List.iterator()
问题:点击Print Doctors按钮触发空指针异常
我正在为控制台应用开发GUI,但点击Print Doctors按钮时遇到无法理解的错误。以下是相关代码:
package com.company; import java.util.*; import java.awt.*; import java.awt.event.*; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import javax.swing.*; public class WestminsterSkinConsultationManagerGUI extends JFrame { private static WestminsterSkinConsultationManager manager; private final ArrayList<Doctor> doctors; private JTextField nameField; private JTextField surnameField; private JTextField dobField; private JTextField mobileField; private JTextField licenseField; private JTextField specializationField; private JTextField deleteField; private JButton addButton; private JButton deleteButton; private JButton printButton; private JButton saveButton; private JButton exitButton; private JTextArea doctorListArea; public WestminsterSkinConsultationManagerGUI() { // Initialize the manager manager = new WestminsterSkinConsultationManager(); this.doctors = new ArrayList<Doctor>(); // Set up the frame setTitle("Westminster Skin Consultation Manager"); setSize(600, 400); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); // Create the panel for the input fields JPanel inputPanel = new JPanel(); inputPanel.setLayout(new GridLayout(7, 2)); // Create the input fields nameField = new JTextField(); surnameField = new JTextField(); dobField = new JTextField(); mobileField = new JTextField(); licenseField = new JTextField(); specializationField = new JTextField(); deleteField = new JTextField(); // Add the input fields to the panel inputPanel.add(new JLabel("Name:")); inputPanel.add(nameField); inputPanel.add(new JLabel("Surname:")); inputPanel.add(surnameField); inputPanel.add(new JLabel("Date of birth:")); inputPanel.add(dobField); inputPanel.add(new JLabel("Mobile number:")); inputPanel.add(mobileField); inputPanel.add(new JLabel("Medical license number:")); inputPanel.add(licenseField); inputPanel.add(new JLabel("Specialization:")); inputPanel.add(specializationField); inputPanel.add(new JLabel("Medical license number to delete:")); inputPanel.add(deleteField); // Create the panel for the buttons JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout(5, 1)); // Create the buttons addButton = new JButton("Add Doctor"); deleteButton = new JButton("Delete Doctor"); printButton = new JButton("Print Doctors"); saveButton = new JButton("Save to File"); exitButton = new JButton("Exit"); // Add the buttons to the panel buttonPanel.add(addButton); buttonPanel.add(deleteButton); buttonPanel.add(printButton); buttonPanel.add(saveButton); buttonPanel.add(exitButton); // Create the panel for the doctor list JPanel listPanel = new JPanel(); doctorListArea = new JTextArea(); doctorListArea.setEditable(false); JScrollPane scrollPane = new JScrollPane(doctorListArea); listPanel.add(scrollPane); // Add the input panel, button panel, and list panel to the frame add(inputPanel, BorderLayout.WEST); add(buttonPanel, BorderLayout.EAST); add(listPanel, BorderLayout.SOUTH); // Add action listeners to the buttons addButton.addActionListener(new AddButtonListener()); deleteButton.addActionListener(new DeleteButtonListener()); printButton.addActionListener(new PrintButtonListener()); saveButton.addActionListener(new SaveButtonListener()); exitButton.addActionListener(new ExitButtonListener()); // Display the frame setVisible(true); } // Inner class for the Add button listener private class AddButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { // Get the input values String name = nameField.getText(); String surname = surnameField.getText(); String dobString = dobField.getText(); String mobile = mobileField.getText(); String license = licenseField.getText(); String specialization = specializationField.getText(); // Create a new doctor object with the input values DateFormat df = new SimpleDateFormat("dd/MM/yyyy"); Date dob = null; try { dob = df.parse(dobString); } catch (ParseException ex) { JOptionPane.showMessageDialog(null, "Error: Invalid date of birth format. Use dd/MM/yyyy."); return; } Doctor doctor = new Doctor(name, surname, dob, mobile, license, specialization); // Add the doctor to the manager manager.addDoctor(doctor); } } // Inner class for the Delete button listener private class DeleteButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { // Get the medical license number to delete String license = deleteField.getText(); // Delete the doctor with the specified medical license number manager.deleteDoctor(license); } } // Inner class for the Print button listener private class PrintButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { // Clear the text area doctorListArea.setText(""); // Print the list of doctors List<Doctor> doctors = manager.getDoctors(); for (Doctor doctor : doctors) { doctorListArea.append("Name: " + doctor.getName() + "\n"); doctorListArea.append("Surname: " + doctor.getSurname() + "\n"); doctorListArea.append("Date of birth: " + doctor.getDateOfBirth() + "\n"); doctorListArea.append("Mobile number: " + doctor.getMobileNumber() + "\n"); doctorListArea.append("Medical license number: " + doctor.getMedicalLicenceNumber() + "\n"); doctorListArea.append("Specialization: " + doctor.getSpecialisation() + "\n\n"); } } } // Inner class for the Save button listener private static class SaveButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { // Save the list of doctors to a file manager.saveToFile(); } } // Inner class for the Exit button listener private static class ExitButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { // Close the program System.exit(0); } } public static void main(String[] args) { new WestminsterSkinConsultationManagerGUI(); } }
触发的错误信息如下:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException: Cannot invoke "java.util.List.iterator()" because "doctors" is null at com.company.WestminsterSkinConsultationManagerGUI$PrintButtonListener.actionPerformed(WestminsterSkinConsultationManagerGUI.java:158) at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1972) at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2313) at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405) at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262) at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:279) at java.desktop/java.awt.Component.processMouseEvent(Component.java:6616) at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3398) at java.desktop/java.awt.Component.processEvent(Component.java:6381) at java.desktop/java.awt.Container.processEvent(Container.java:2266) at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:4991) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2324) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4823) at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4948) at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4575) at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4516) at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2310) at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2780) at java.desktop/java.awt.Component.dispatchEvent(Component.java:4823) at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:775) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:720) at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:714) at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:97) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:747) at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:745) at java.base/java.security.AccessController.doPrivileged(AccessController.java:399) at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:86) at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:744) at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203) at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124) at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109) at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101) at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
错误原因分析
错误堆栈明确指出,空指针异常发生在PrintButtonListener的for (Doctor doctor : doctors)循环处,原因是调用manager.getDoctors()返回了null。当尝试遍历一个null的List时,JVM会抛出NullPointerException,因为无法对null对象调用iterator()方法。
问题根源在于WestminsterSkinConsultationManager类的getDoctors()方法实现:要么该方法没有初始化存储医生的List就返回,要么在某些情况下返回了null而不是空列表。
解决方法
方法一:修复WestminsterSkinConsultationManager的getDoctors()方法
确保存储医生的List在类初始化时就被创建,并且getDoctors()方法始终返回一个有效的List(即使是空列表,也不要返回null)。示例实现如下:
public class WestminsterSkinConsultationManager { // 初始化医生列表,避免null private final List<Doctor> doctors = new ArrayList<>(); // 添加医生的方法 public void addDoctor(Doctor doctor) { doctors.add(doctor); } // 删除医生的方法 public void deleteDoctor(String license) { doctors.removeIf(d -> d.getMedicalLicenceNumber().equals(license)); } // 获取医生列表,返回副本避免外部修改内部状态 public List<Doctor> getDoctors() { return new ArrayList<>(doctors); } // 其他方法... }
方法二:在GUI代码中增加空值判断
即使getDoctors()可能返回null,也可以在GUI的打印逻辑中提前处理,避免崩溃并给出友好提示:
修改PrintButtonListener的代码:
private class PrintButtonListener implements ActionListener { public void actionPerformed(ActionEvent e) { doctorListArea.setText(""); List<Doctor> doctors = manager.getDoctors(); // 增加空判断和空列表判断 if (doctors == null || doctors.isEmpty()) { doctorListArea.append("当前没有医生数据"); return; } for (Doctor doctor : doctors) { doctorListArea.append("Name: " + doctor.getName() + "\n"); doctorListArea.append("Surname: " + doctor.getSurname() + "\n"); doctorListArea.append("Date of birth: " + doctor.getDateOfBirth() + "\n"); doctorListArea.append("Mobile number: " + doctor.getMobileNumber() + "\n"); doctorListArea.append("Medical license number: " + doctor.getMedicalLicenceNumber() + "\n"); doctorListArea.append("Specialization: " + doctor.getSpecialisation() + "\n\n"); } } }
建议优先使用方法一,从根源上避免返回null的情况,这是更规范的Java编程实践。方法二则作为防御性编程的补充,进一步提升程序稳定性。
内容的提问来源于stack exchange,提问作者Himasha
相关产品推荐
相关产品推荐

