
本文详解如何在Swing中对JTable指定列(如“Weight”)按条件(如Type & Size为"R6")安全求和,同时确保原始表格数据完全不变——关键在于避免在遍历过程中调用removeRow(),改用只读访问与独立累加逻辑。
本文详解如何在swing中对jtable指定列(如“weight”)按条件(如type & size为"r6")安全求和,同时确保原始表格数据完全不变——关键在于避免在遍历过程中调用`removerow()`,改用只读访问与独立累加逻辑。
在Swing应用中,使用JTable进行数据展示与聚合计算是常见需求。但初学者常误在求和逻辑中直接操作原始表格模型(如调用removeRow()),导致源数据被意外修改、行索引错乱甚至ArrayIndexOutOfBoundsException。本文以实际案例为基础,提供零副作用、线程安全、可扩展的列求和解决方案。
? 核心问题定位
原代码中存在两个关键错误:
- 边遍历边删除:for (int i = 0; i
- 空值校验位置错误:if (dataModel.getValueAt(i, 2) == null) { dataModel.removeRow(i); } 在求和循环内执行,既破坏原始数据,又干扰后续条件判断(如mark.equals("R6"))。
✅ 正确原则:原始数据只读(Read-Only),聚合逻辑与数据模型解耦。
✅ 推荐实现:纯读取 + 条件累加
以下为修复后的核心求和逻辑(已集成至ActionListener):
sumButton.addActionListener(e -> {
DefaultTableModel dataModel = (DefaultTableModel) dataTable.getModel();
DefaultTableModel summaryModel = (DefaultTableModel) summeryTable.getModel();
// 1. 清空汇总表(仅清空结果,不碰源数据)
int rowCount = summaryModel.getRowCount();
for (int j = rowCount - 1; j >= 0; j--) {
summaryModel.removeRow(j);
}
// 2. 安全遍历原始表:只读取,不修改
BigDecimal totalR6Weight = BigDecimal.ZERO;
for (int i = 0; i < dataModel.getRowCount(); i++) {
// 跳过空值行(如标题行"Slab"、"Column"),不删除!
Object typeSizeObj = dataModel.getValueAt(i, 2);
if (typeSizeObj == null || !(typeSizeObj instanceof String)) {
continue;
}
String typeSize = (String) typeSizeObj;
// 仅对目标类型(如"R6")累加权重
if ("R6".equals(typeSize)) {
Object weightObj = dataModel.getValueAt(i, 3);
if (weightObj != null) {
try {
BigDecimal weight = new BigDecimal(weightObj.toString().trim());
totalR6Weight = totalR6Weight.add(weight).setScale(2, RoundingMode.HALF_UP);
} catch (NumberFormatException ex) {
// 忽略非法数字格式(如空字符串、非数字字符)
System.err.println("Invalid weight value at row " + i + ": " + weightObj);
}
}
}
}
// 3. 将结果写入汇总表(单行示例,可扩展为多组分组)
summaryModel.addRow(new Object[]{"R6", totalR6Weight});
});⚠️ 关键注意事项
- 永远不要在for循环中调用removeRow():若需过滤数据,应先收集有效行索引,再倒序删除;但本场景无需删除,故直接continue跳过;
- 显式空值与类型检查:getValueAt()返回Object,必须判空并强转,避免NullPointerException;
- 数值解析防御性编程:用try-catch捕获NumberFormatException,防止用户输入非数字内容导致崩溃;
- BigDecimal精度控制:.setScale(2, RoundingMode.HALF_UP) 确保货币类数值四舍五入到小数点后两位;
- UI线程安全:所有Swing组件操作均在EDT(Event Dispatch Thread)中执行(本例由ActionListener保证),无需额外SwingUtilities.invokeLater。
? 进阶建议
- 若需支持多类型分组汇总(如同时统计"R6"、"T10"、"T20"),可改用Map
存储各组累加值,最后批量写入summaryModel; - 对大数据量表格,可考虑将求和逻辑抽离为独立服务方法,提升可测试性;
- 使用TableRowSorter时,注意getValueAt()获取的是视图行号,需通过convertRowIndexToModel()转换为模型行号——本例未启用排序,故无需处理。
遵循以上实践,即可在保持dataTable原始结构与内容100%不变的前提下,稳定、准确、健壮地完成条件列求和,并将结果呈现于summeryTable。









