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

在TableModelListener中调用setValue触发StackOverflowError问题求助

解决TableModelListener中调用setValue导致无限循环的问题

问题根源

你遇到的无限循环问题,本质是因为调用setValue(...)方法会触发新的TableModelEvent事件,而这个事件又会被你的TableModelListener捕获,再次执行乘法运算并调用setValue(...),形成了无限递归的循环,最终导致程序抛出异常。

解决方案

要打破这个循环,我们需要在修改表格值的时候临时移除监听器,或者添加判断条件,只在特定情况下执行修改逻辑。下面给你两种可行的实现方式:

方式一:临时移除并重新添加监听器

这种方式简单直接,在执行setValue(...)前先把监听器从模型中移除,修改完成后再加回去,避免触发新的事件:

public void populateTable() {
    DefaultTableModel employeeModel = (DefaultTableModel) jTable1.getModel();
    TableModelListener listener = new TableModelListener() {
        public void tableChanged(TableModelEvent e) {
            // 先移除监听器,防止触发新事件
            employeeModel.removeTableModelListener(this);
            
            Integer totalDue = 0;
            // 这里写你的乘法运算逻辑
            // 示例:假设计算第2列和第3列的乘积,放到第4列
            int row = e.getFirstRow();
            if (e.getColumn() == 1 || e.getColumn() == 2) { // 只在修改第2、3列时计算
                Integer quantity = (Integer) employeeModel.getValueAt(row, 1);
                Integer price = (Integer) employeeModel.getValueAt(row, 2);
                totalDue = quantity * price;
                employeeModel.setValueAt(totalDue, row, 3);
            }
            
            // 重新添加监听器,恢复监听
            employeeModel.addTableModelListener(this);
        }
    };
    employeeModel.addTableModelListener(listener);
}

方式二:添加状态标记,跳过递归触发的事件

可以用一个布尔变量标记当前是否正在修改值,当处于修改状态时,直接跳过listener的逻辑:

public void populateTable() {
    DefaultTableModel employeeModel = (DefaultTableModel) jTable1.getModel();
    // 标记是否正在更新表格值
    AtomicBoolean isUpdating = new AtomicBoolean(false);
    
    employeeModel.addTableModelListener(new TableModelListener() {
        public void tableChanged(TableModelEvent e) {
            // 如果正在更新,直接返回,避免循环
            if (isUpdating.get()) {
                return;
            }
            
            Integer totalDue = 0;
            int row = e.getFirstRow();
            if (e.getColumn() == 1 || e.getColumn() == 2) {
                Integer quantity = (Integer) employeeModel.getValueAt(row, 1);
                Integer price = (Integer) employeeModel.getValueAt(row, 2);
                totalDue = quantity * price;
                
                // 设置标记为正在更新
                isUpdating.set(true);
                employeeModel.setValueAt(totalDue, row, 3);
                // 完成后重置标记
                isUpdating.set(false);
            }
        }
    });
}

额外提示

  • 尽量缩小触发修改的范围:比如只在修改特定列(比如数量、单价列)时才计算总价,避免对无关列的修改触发逻辑,减少不必要的事件。
  • 注意空值处理:如果表格单元格可能为空,要先判断getValueAt的结果是否为null,避免NullPointerException。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:51:55