首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Apache POI 讀取 Excel 空指針異常:getFirstCellNum/getLastCellNum 避坑指南

     編輯:程式設計綜合問答

使用 POI 遍歷 Excel 行單元格時,row.getFirstCellNum() 或 row.getLastCellNum() 拋出 NullPointerException,但單元格值能正常讀取。這是經典的 空行/空單元格未判空 問題。

報錯代碼

for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
    Cell cell = row.getCell(j); // 這裡可能拿到 null
    String value = cell.getStringCellValue(); // NPE 在這行
}

異常堆疊:Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException

根本原因

  • getFirstCellNum() 返回該行第一個非空單元格索引
  • getLastCellNum() 返回該行最後一個非空單元格索引 + 1
  • 中間的空單元格 row.getCell(j) 返回 null
  • 直接調用 cell.getStringCellValue() 炸裂

修復代碼

// 1. 先判斷 row 是否為 null
if (row == null) continue;

// 2. 獲取索引範圍
int firstCol = row.getFirstCellNum();
int lastCol = row.getLastCellNum();

// 3. 遍歷時每個 cell 都要判空
for (int j = firstCol; j < lastCol; j++) {
    Cell cell = row.getCell(j);
    if (cell == null) {
        continue; // 或設置默認值
    }
    
    // 4. 根據單元格類型安全取值
    String value = "";
    switch (cell.getCellTypeEnum()) {
        case STRING:
            value = cell.getStringCellValue();
            break;
        case NUMERIC:
            if (DateUtil.isCellDateFormatted(cell)) {
                value = cell.getDateCellValue().toString();
            } else {
                value = String.valueOf(cell.getNumericCellValue());
            }
            break;
        case BOOLEAN:
            value = String.valueOf(cell.getBooleanCellValue());
            break;
        case FORMULA:
            value = cell.getCellFormula();
            break;
        case BLANK:
        case _NONE:
        case ERROR:
        default:
            value = "";
    }
    // 處理 value...
}

最佳實踐:封裝工具方法

public static String getCellValueAsString(Cell cell) {
    if (cell == null) return "";
    return switch (cell.getCellTypeEnum()) {
        case STRING -> cell.getStringCellValue();
        case NUMERIC -> DateUtil.isCellDateFormatted(cell) 
            ? cell.getDateCellValue().toString() 
            : String.valueOf(cell.getNumericCellValue());
        case BOOLEAN -> String.valueOf(cell.getBooleanCellValue());
        case FORMULA -> cell.getCellFormula();
        default -> "";
    };
}

補充:POI 版本差異

  • POI 3.x:cell.getCellType() 返回 int,用 Cell.CELL_TYPE_STRING 等常量
  • POI 4.x/5.x:cell.getCellTypeEnum() 返回 CellType 枚舉,更安全
  • 推薦升級到 POI 5.2.3+,修復大量 Bug,支持 .xlsx 流式讀取(SXSSF)

記住鐵律:POI 讀取單元格前必須判空,判空,再判空!

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved