Java实现XLSX转JSON时遇IllegalStateException异常的原因排查
嘿,这个问题我之前做Excel转JSON工具的时候也踩过坑!咱们来一步步拆解原因和解决办法:
核心原因分析
你遇到的异常本质是你尝试从一个实际存储为字符串类型的单元格中读取数值,但代码里的类型判断逻辑出了问题,常见的两种情况:
判断和取值的不是同一个单元格
你的代码里,判断类型用的是rw.getCell(j)(当前循环行的第j列单元格),但取值却用了sht.getRow(0).getCell(j)(第一行的第j列单元格)。如果第一行的这个单元格是字符串类型,哪怕当前行的单元格是数值类型,执行到取值那一步时还是会报错!这是最容易忽略的细节。单元格显示为数值,但实际存储为字符串
Excel里经常会出现这种情况:比如用户手动输入了带单引号的数字(比如'123),或者通过导入、公式生成了文本型数字。此时POI会严格按照单元格的实际存储类型识别,而不是它显示出来的样子——也就是说单元格类型是STRING,但看起来像数值,这时候你直接调用getNumericCellValue()就会抛出异常。
针对性解决方案
方案1:确保判断和取值的是同一个单元格
如果你的逻辑是要处理当前行的单元格,把代码改成这样:
else if (rw.getCell(j).getCellType() == Cell.CELL_TYPE_NUMERIC) { // 现在判断和取值的都是rw.getCell(j)这个单元格 key = "" + rw.getCell(j).getNumericCellValue(); }
如果你的需求确实是要获取第一行的单元格值,那应该先判断第一行单元格的类型,而不是当前行的:
// 先拿到第一行的目标单元格 Cell headerCell = sht.getRow(0).getCell(j); if (headerCell.getCellType() == Cell.CELL_TYPE_NUMERIC) { key = "" + headerCell.getNumericCellValue(); } else if (headerCell.getCellType() == Cell.CELL_TYPE_STRING) { key = headerCell.getStringCellValue(); } // 别忘了处理其他类型(比如空白、公式等)的情况
方案2:处理文本型数字的情况
如果单元格是显示为数值的字符串,推荐用POI的DataFormatter工具类,它可以统一获取单元格的显示文本,再自行解析成数值:
// 初始化DataFormatter,全局初始化一次就行,不用每次循环都创建 DataFormatter formatter = new DataFormatter(); Cell targetCell = rw.getCell(j); // 获取单元格显示的文本内容 String cellDisplayText = formatter.formatCellValue(targetCell); // 尝试把文本转成数值 try { double numericValue = Double.parseDouble(cellDisplayText); key = String.valueOf(numericValue); } catch (NumberFormatException e) { // 转失败说明不是合法数字,直接用原文本 key = cellDisplayText; }
如果你确定单元格应该是数值,也可以尝试强制转换单元格类型(注意:这会修改Excel文件中的数据,谨慎使用):
Cell cell = rw.getCell(j); if (cell.getCellType() == Cell.CELL_TYPE_STRING) { try { // 尝试把字符串单元格转为数值类型 cell.setCellType(Cell.CELL_TYPE_NUMERIC); key = "" + cell.getNumericCellValue(); } catch (IllegalStateException e) { // 转换失败,说明字符串不是合法数字,用原字符串 key = cell.getStringCellValue(); } }
小提示:升级POI的类型判断方式
如果你用的是POI 3.17及以上版本,Cell.CELL_TYPE_NUMERIC这类常量已经被废弃了,推荐使用CellType枚举类来判断类型,代码更规范:
if (cell.getCellType() == CellType.NUMERIC) { // 处理数值类型 } else if (cell.getCellType() == CellType.STRING) { // 处理字符串类型 }
内容的提问来源于stack exchange,提问作者Alok Chahande

