You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用LinkedList读写文件到JFrame的JTable时遇IndexOutOfBoundsException

问题分析与修复方案

核心错误点

1. addContactToFile 方法逻辑错误

原代码直接通过 fileContacts.get(0)、get(1)、get(2) 读取数据,完全误解了二维LinkedList的结构:fileContacts 中每个元素是单个联系人的信息集合(包含姓名、电话、邮箱),而非所有联系人的单个字段。第一次添加联系人时,fileContacts 只有1个元素,调用 get(1) 直接触发 IndexOutOfBoundsException。同时该方法接收整个联系人集合作为参数完全多余,只需传入刚创建的单个联系人即可。

2. loadFileContents 方法未清空全局集合

每次加载文件时,fileContacts 没有被清空,导致旧数据与新读取的数据累加,不仅造成表格重复显示,还会在后续操作中引发索引混乱。

3. 文件读写格式不匹配

原代码写入时额外添加空行,但读取时未跳过空行,会导致空行被当作联系人字段存入集合,破坏“每3行一个联系人”的结构。


修复后的完整代码

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.LinkedList;

public class FileContentApp {
    private static final String FILE_PATH = "contacts.txt";
    private static DefaultTableModel tableModel;
    public static LinkedList<LinkedList<String>> fileContacts = new LinkedList<>();

    public static void main(String[] args) {
        JFrame frame = new JFrame("Contact File");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 300);
        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().setBackground(Color.WHITE);

        JPanel topPanel = new JPanel(new BorderLayout());
        topPanel.setBackground(Color.WHITE);
        JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        buttonPanel.setBackground(Color.WHITE);
        JLabel titleLabel = new JLabel("Contacts");
        titleLabel.setHorizontalAlignment(SwingConstants.CENTER);
        topPanel.add(titleLabel, BorderLayout.NORTH);
        JButton addButton = new JButton("+");
        addButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                showDialog(frame);
            }
        });
        JButton settingButton = new JButton("...");
        buttonPanel.add(addButton);
        buttonPanel.add(settingButton);
        topPanel.add(buttonPanel, BorderLayout.EAST);
        frame.getContentPane().add(topPanel, BorderLayout.NORTH);

        JPanel contentPanel = new JPanel(new BorderLayout());
        contentPanel.setBackground(Color.WHITE);
        JTable table = createTable();
        JScrollPane scrollPane = new JScrollPane(table);
        contentPanel.add(scrollPane, BorderLayout.CENTER);
        frame.getContentPane().add(contentPanel, BorderLayout.CENTER);

        loadFileContents();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static JTable createTable() {
        tableModel = new DefaultTableModel();
        tableModel.addColumn("Name");
        tableModel.addColumn("Phone");
        tableModel.addColumn("Email");
        JTable table = new JTable(tableModel);
        table.setGridColor(Color.LIGHT_GRAY);
        table.setShowGrid(true);
        return table;
    }

    private static void showDialog(JFrame parentFrame) {
        LinkedList<String> listContact = new LinkedList<>();
        JDialog dialog = new JDialog(parentFrame, "Add Contact", true);
        dialog.setSize(300, 200);
        dialog.setLayout(new BorderLayout());
        dialog.setLocationRelativeTo(parentFrame);

        JPanel inputPanel = new JPanel(new GridLayout(3, 2));
        inputPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        JLabel nameLabel = new JLabel("Name : ");
        JTextField nameField = new JTextField();
        JLabel phoneLabel = new JLabel("Phone : ");
        JTextField phoneField = new JTextField();
        JLabel emailLabel = new JLabel("Email : ");
        JTextField emailField = new JTextField();

        inputPanel.add(nameLabel);
        inputPanel.add(nameField);
        inputPanel.add(phoneLabel);
        inputPanel.add(phoneField);
        inputPanel.add(emailLabel);
        inputPanel.add(emailField);

        JPanel buttonPanel = new JPanel();
        buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
        JButton addButton = new JButton("Add");
        addButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                String name = nameField.getText();
                String phone = phoneField.getText();
                String email = emailField.getText();
                listContact.add(name);
                listContact.add(phone);
                listContact.add(email);
                fileContacts.add(listContact);
                addContactToFile(listContact); // 传入单个联系人而非整个集合
                loadFileContents();
                dialog.dispose();
            }
        });
        buttonPanel.add(addButton);

        dialog.add(inputPanel, BorderLayout.CENTER);
        dialog.add(buttonPanel, BorderLayout.SOUTH);
        dialog.setVisible(true);
    }


    private static void addContactToFile(LinkedList<String> contact) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(FILE_PATH, true))) {
            // 写入单个联系人的三个字段,每行一个
            writer.write(contact.get(0));
            writer.newLine();
            writer.write(contact.get(1));
            writer.newLine();
            writer.write(contact.get(2));
            writer.newLine();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void loadFileContents() {
        tableModel.setRowCount(0); // 清空表格
        fileContacts.clear(); // 清空全局联系人集合,避免数据累加

        try (BufferedReader reader = new BufferedReader(new FileReader(FILE_PATH))) {
            String line;
            int lineCount = 0;
            LinkedList<String> currentContact = null;
            while ((line = reader.readLine()) != null) {
                line = line.trim();
                if (line.isEmpty()) {
                    continue; // 跳过空行,避免破坏结构
                }
                if (lineCount % 3 == 0) {
                    currentContact = new LinkedList<>();
                    fileContacts.add(currentContact);
                }
                currentContact.add(line);
                lineCount++;
            }

            // 将集合数据同步到表格
            for (LinkedList<String> contact : fileContacts) {
                // 确保每个联系人有三个字段,避免表格报错
                if (contact.size() == 3) {
                    tableModel.addRow(contact.toArray());
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

额外优化建议

  1. 封装联系人数据:创建一个Contact类(包含name、phone、email属性)替代二维LinkedList,代码可读性和可维护性会大幅提升,也能避免集合操作的索引错误。
  2. 输入验证:在添加联系人时,检查姓名、电话等字段是否为空,避免无效数据写入文件。
  3. 删除功能扩展:可通过JTable的选中事件获取行索引,调用fileContacts.remove(index)和tableModel.removeRow(index)实现逐条删除,同时同步更新文件。

内容的提问来源于stack exchange,提问作者Franco Luis Rosel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:48:05