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

JTable开启自动排序后添加行触发数组越界异常问题

解决JTable排序后添加行触发ArrayIndexOutOfBoundsException的问题

这个问题的核心原因很明确:当你开启setAutoCreateRowSorter(true)后,JTable的视图索引和TableModel的模型索引不再一一对应。你的TableModelListener中拿到的arg0.getFirstRow()是模型层面的行索引,但直接调用table.getValueAt(row, 0)时,JTable会把这个索引当成视图层面的索引来使用——排序后两者的映射关系已经改变,自然会出现索引越界的错误。

两种可行的解决方案

方案1:直接从TableModel获取数据(最简单)

既然事件是来自TableModel的,完全不需要通过JTable来获取新增行的数据,直接从tableModel里取就好,模型索引在模型里肯定是有效的:

tableModel.addTableModelListener(new TableModelListener(){
    @Override
    public void tableChanged(TableModelEvent arg0) {
        if(arg0.getType() == TableModelEvent.INSERT){
            int modelRow = arg0.getFirstRow();
            // 直接从模型获取值,不需要经过JTable
            System.out.println(tableModel.getValueAt(modelRow, 0));
        }
    }
});

方案2:将模型索引转换为视图索引(如果必须通过JTable操作)

如果你确实需要通过JTable来操作这行数据(比如选中它、修改UI样式等),需要用JTable.convertRowIndexToView()方法把模型索引转换成视图索引,同时记得判断转换后的索引是否有效(避免极端情况):

tableModel.addTableModelListener(new TableModelListener(){
    @Override
    public void tableChanged(TableModelEvent arg0) {
        if(arg0.getType() == TableModelEvent.INSERT){
            int modelRow = arg0.getFirstRow();
            // 转换模型索引到视图索引
            int viewRow = table.convertRowIndexToView(modelRow);
            // 检查转换后的索引是否有效(排序后新增行肯定在视图里,这步是防御性编程)
            if(viewRow != -1){
                System.out.println(table.getValueAt(viewRow, 0));
            }
        }
    }
});

为什么你之前的尝试没生效?

你提到尝试过转换行索引但没解决问题,大概率是搞反了转换方向:比如误用了convertViewIndexToModel()(把视图索引转模型索引),而不是convertRowIndexToView()(把模型索引转视图索引)。另外,直接用insertRow()和addRow()本质上没有区别,核心问题还是索引的混淆。

修改后的完整SSCCE示例

这里用方案1的写法修改你的代码,确保可以正常运行:

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import java.awt.GridLayout;
import javax.swing.JTable;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import javax.swing.JScrollPane;

public class MainTable extends JDialog {
    private static final long serialVersionUID = 156332386872772726L;
    private final JPanel contentPanel = new JPanel();
    private DefaultTableModel tableModel;
    private JTable table;

    public static void main(String[] args) {
        try {
            MainTable dialog = new MainTable();
            dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
            dialog.setVisible(true);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public MainTable() {
        setBounds(100, 100, 450, 300);
        getContentPane().setLayout(new BorderLayout());
        contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
        getContentPane().add(contentPanel, BorderLayout.CENTER);
        contentPanel.setLayout(new GridLayout(1, 0, 0, 0));
        {
            JScrollPane scrollPane = new JScrollPane();
            contentPanel.add(scrollPane);
            {
                table = new JTable();
                table.setAutoCreateRowSorter(true);
                tableModel = new DefaultTableModel(new String[]{"first","second"},0);
                table.setModel(tableModel);
                tableModel.addTableModelListener(new TableModelListener(){
                    @Override
                    public void tableChanged(TableModelEvent arg0) {
                        if(arg0.getType() == TableModelEvent.INSERT){
                            int modelRow = arg0.getFirstRow();
                            // 直接从模型获取数据,避免索引混淆
                            System.out.println(tableModel.getValueAt(modelRow, 0));
                        }
                    }
                });
                scrollPane.setViewportView(table);
            }
        }
        {
            JPanel buttonPane = new JPanel();
            buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
            getContentPane().add(buttonPane, BorderLayout.SOUTH);
            {
                JButton okButton = new JButton("Add");
                okButton.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent arg0) {
                        int row = tableModel.getRowCount();
                        tableModel.addRow(new Object[]{row,row});
                    }
                });
                buttonPane.add(okButton);
                getRootPane().setDefaultButton(okButton);
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者lution

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:41:23