使用 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() 返回該行最後一個非空單元格索引 + 1row.getCell(j) 返回 nullcell.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 -> "";
};
}
cell.getCellType() 返回 int,用 Cell.CELL_TYPE_STRING 等常量cell.getCellTypeEnum() 返回 CellType 枚舉,更安全記住鐵律:POI 讀取單元格前必須判空,判空,再判空!