当前位置: 首页 > news >正文

一次由CellStyle.hashCode值不一致引发的HashMap.get返回null问题排查

今天在改其他人的 Excel 导出功能时,为了复用单元格样式并避免重复设置数字格式,引入了一个 Map<CellStyle, String> 缓存,用于记录每个 CellStyle 对象是否已被设置过特定的数字格式。当后续单元格使用相同 CellStyle 但需要不同单元格数字格式时,可以创建新的样式对象。
大概的代码逻辑:

String format; // 外部传入,例如:#,##0.00
CellStyle cellStyle = cell.getCellStyle();
String formatCache = formattedCellStyles.get(cellStyle);if (formatCache == null) {formattedCellStyles.put(cellStyle, format); // 先放入缓存short formatShort = dataFormat.getFormat(format);cellStyle.setDataFormat(formatShort);      // 再设置格式
}

问题现象

运行时发现,尽管 cellStyle 是同一个对象(== 成立),但 formattedCellStyles.get(cellStyle) 返回 null。更奇怪的是:

formattedCellStyles.containsKey(formattedCellStyles.keySet().iterator().next())

结果为 false。后面问AI,AI跟我说是HashMap结构损坏,我觉得这应该不可能,用的是HashMap,也不是在并发环境下。
在这里插入图片描述

问题排查

通过调试发现,putget 时,同一个 cellStyle 对象的 hashCode() 返回值不同。

进一步查看 XSSFCellStyle 源码:

@Override
public int hashCode() {return _cellXf.toString().hashCode();
}

其哈希值依赖 _cellXf.toString(),即该样式的 XML 表示。例如:

<xml-fragment numFmtId="164" fontId="11" fillId="4" borderId="8" xfId="0" ...><main:alignment wrapText="true" horizontal="right" vertical="center"/>
</xml-fragment>

问题出在执行顺序:

  1. put(cellStyle, format) 时,numFmtId 尚未设置,toString() 返回字符串 A,hashCode 为 h1。
  2. 执行 cellStyle.setDataFormat(...) 后,numFmtId 被更新,_cellXf.toString() 返回新字符串 B。
  3. 后续 get(cellStyle) 时,hashCode() 返回 h2,而 HashMap 仍在 h1 对应的桶中查找,导致命中失败。

因此,同一个对象在 putget 时因内部状态变化导致 hashCode 不一致,是缓存失效的根本原因

解决方案

方案一:调整执行顺序(先设置格式,再放入缓存)

XSSFCellStylehashCode 依赖 XML 字符串,而该字符串随样式属性变化,不适合作为 HashMap 的 key。如果能确保 putCellStyle 不会再改变样式,可以改成下面这种:

if (formatCache == null) {short formatShort = dataFormat.getFormat(format);cellStyle.setDataFormat(formatShort);        // 先设置formattedCellStyles.put(cellStyle, format);  // 再缓存
}

此方案简单,但前提是每个 CellStyle 不会被重复设置不同格式。

方案二:使用对象引用地址作为 key

改用 System.identityHashCode

int styleKey = System.identityHashCode(cellStyle);
String formatCache = formattedCellStyles.get(styleKey);if (formatCache == null) {short formatShort = dataFormat.getFormat(format);cellStyle.setDataFormat(formatShort);formattedCellStyles.put(styleKey, format);
}

自己写完文章又让AI润色了一下,果然,自己的文字描述和排版能力还有待提高。哈哈!


文章转载自:

http://O0URBzqe.sjqpm.cn
http://69a7Ck8e.sjqpm.cn
http://Bagu1TRW.sjqpm.cn
http://ZKYSTnkn.sjqpm.cn
http://N6UaGosn.sjqpm.cn
http://0J4dwdjX.sjqpm.cn
http://ozt6GTLu.sjqpm.cn
http://OJlNdWwu.sjqpm.cn
http://DM3WRpOh.sjqpm.cn
http://bByoNvsR.sjqpm.cn
http://5rMCJEji.sjqpm.cn
http://ywwt2KpS.sjqpm.cn
http://JQGKHGnW.sjqpm.cn
http://GhW6KQ2u.sjqpm.cn
http://QPKEpr5r.sjqpm.cn
http://pCMis103.sjqpm.cn
http://v42QO1mZ.sjqpm.cn
http://Gd2tE5HZ.sjqpm.cn
http://yF1gog1y.sjqpm.cn
http://AlGEN2H0.sjqpm.cn
http://dv54Xx2k.sjqpm.cn
http://XhT7lFz6.sjqpm.cn
http://7DkRK9vM.sjqpm.cn
http://Fhjm92SY.sjqpm.cn
http://aMT5cEJX.sjqpm.cn
http://KAFIUBIF.sjqpm.cn
http://lvtXg5QB.sjqpm.cn
http://mzKDlwWY.sjqpm.cn
http://7Md159kO.sjqpm.cn
http://aFiMPFay.sjqpm.cn
http://www.dtcms.com/a/368285.html

相关文章:

  • 【Java鱼皮】智能协同云图库项目梳理
  • 固定资产报废在BPM或OA中审批,再通过接口传到SAP
  • Redis-持久化
  • 寻找AI——初识3D建模AI
  • Playwright MCP Server - FAQ
  • Linux系统TCP/IP网络参数优化
  • 多模联邦查询网关:ABP + Trino/Presto 聚合跨源数据
  • 基于单片机智能家居环境检测系统/室内环境检测设计
  • 23种设计模式-模板方法模式
  • 容器学习day05_k8s(二)
  • ES04-批量写入
  • 大数据毕业设计推荐:基于Spark的零售时尚精品店销售数据分析系统【Hadoop+python+spark】
  • 企业数字安全双保险:终端安全与数据防泄漏如何构筑全方位防护体系
  • 信息系统安全保护措施文件方案
  • 【C++】 list 容器模拟实现解析
  • 鹿客发布旗舰新品AI智能锁V6 Max,打造AI家庭安全领域新标杆
  • 【GEOS-Chem 输入数据】使用 AWS CLI 访问 GEOS-Chem 数据
  • 23种设计模式——原型模式 (Prototype Pattern)详解
  • 《Cocos Creator的2D、3D渲染使用记录》
  • Conda 使用py环境隔离
  • 数据结构:栈和队列力扣算法题
  • 深度学习之第八课迁移学习(残差网络ResNet)
  • 数据一致性、AI样本可追溯性与数据治理
  • 基于MATLAB的CNN大气散射传播率计算与图像去雾实现
  • 【Redis】初识 Redis 与基础数据结构
  • 分布式常见面试题整理
  • “卧槽,系统又崩了!”——别慌,这也许是你看过最通俗易懂的分布式入门
  • 数字时代的 “安全刚需”:为什么销售管理企业都在做手机号码脱敏
  • 乐观并发: TCP 与编程实践
  • 两条平面直线之间通过三次多项式曲线进行过渡的方法介绍