如何将Excel多列数据写入HashMap?求Java代码优化方案
优化Excel列读取至HashMap的动态实现方案
我目前用Java实现了从Excel逐列读取数据并写入HashMap的逻辑,但用switch case处理不同列的方式扩展性极差,后续列数增加时维护成本很高。以下是当前的实现代码:
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.poi.ss.usermodel.DataFormatter; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class testclass { public static Map<String,List<String>> getInputData(File dmnPath, File excelPath) throws IOException { //preparation input data list Map<String,List<String>> inputMap =new HashMap<String,List<String>>(); List<String> values = new ArrayList<>(); List<String> values2 = new ArrayList<>(); List<String> values3 = new ArrayList<>(); List<String> values4 = new ArrayList<>(); List<String> values5 = new ArrayList<>(); List<String> values6 = new ArrayList<>(); List<String> values7 = new ArrayList<>(); List<String> values8 = new ArrayList<>(); // Reading file from local directory FileInputStream file = new FileInputStream(excelPath); ExtractingHeaders ext = new ExtractingHeaders(); // Create Workbook instance holding reference to .xlsx file XSSFWorkbook XS = new XSSFWorkbook(file); int numberofsheets = XS.getNumberOfSheets(); for (int i = 0; i < numberofsheets; i++) { if (XS.getSheetName(i).equalsIgnoreCase("Sheet1")) { XSSFSheet XSS = XS.getSheetAt(i); DataFormatter formatter = new DataFormatter(); int k = 0; for(String key: ext.getInputHeaders(dmnPath, excelPath)) { // headerDetails.getInputParam() nned to delete inputMap.put(key, new ArrayList<String>()); Iterator<Row> r = XSS.iterator(); while (r.hasNext()) { // loop for excel row count Row row = r.next(); if (row.getRowNum() == 0) { continue; } String cellValue; switch(k) { // Need to replace switch case to dynamic case 0: cellValue = formatter.formatCellValue(row.getCell(k)); if (cellValue.equals("")) { values.add(null); } else { values.add(cellValue); } inputMap.put(key, values); break; case 1: cellValue = formatter.formatCellValue(row.getCell(k)); if (cellValue.equals("")) { values2.add(null); } else { values2.add(cellValue); } inputMap.put(key, values2); break; case 2: cellValue = formatter.formatCellValue(row.getCell(k)); if (cellValue.equals("")) { values3.add(null); } else { values3.add(cellValue); } inputMap.put(key, values3); break; case 3: cellValue = formatter.formatCellValue(row.getCell(k)); if (cellValue.equals("")) { values4.add(null); } else { values4.add(cellValue); } inputMap.put(key, values4); break; case 4: cellValue = formatter.formatCellValue(row.getCell(k)); if (cellValue.equals("")) { values5.add(null); } else { values5.add(cellValue); } inputMap.put(key, values5); break; case 5: cellValue = formatter.formatCellValue(row.getCell(k)); if (cellValue.equals("")) { values6.add(null); } else { values6.add(cellValue); } inputMap.put(key, values6); break; case 6: cellValue = formatter.formatCellValue(row.getCell(k)); if (cellValue.equals("")) { values7.add(null); } else { values7.add(cellValue); } inputMap.put(key, values7); break; case 7: cellValue = formatter.formatCellValue(row.getCell(k)); if (cellValue.equals("")) { values8.add(null); } else { values8.add(cellValue); } inputMap.put(key, values8); break; default: System.out.println("No case statemnt in ReadExcelTestCase input class"); } } k++; } } // Closing file output streams XS.close(); file.close(); } return inputMap; } }
期望实现动态处理任意列数的逻辑,示例Excel对应的预期输出如下:
{Column1=[C1,C2,C3], Column2=[C2,C3,C4], Column3=[4,56,3], Column4=[C4,C5,C6], Column5=[C5,C6,C7], Column6=[4,7,9], Column7=[C7,C8,C9], Column8=[5,5,6]}
优化后的动态实现方案
核心思路是移除硬编码的List变量和switch分支,通过动态关联表头与列索引,统一处理每一列的数据:
- 先获取所有表头,为每个表头初始化对应的空List并存入HashMap
- 遍历Excel行(跳过表头行),对每一行按列索引依次处理,将单元格值加入对应表头的List中
- 使用try-with-resources自动关闭IO资源,避免手动关闭的异常风险
优化后的完整代码:
import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.poi.ss.usermodel.DataFormatter; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.xssf.usermodel.XSSFSheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; public class ExcelReader { public static Map<String, List<String>> getInputData(File dmnPath, File excelPath) throws IOException { Map<String, List<String>> inputMap = new HashMap<>(); ExtractingHeaders ext = new ExtractingHeaders(); // 获取所有表头,提前初始化每个表头对应的空List List<String> headers = ext.getInputHeaders(dmnPath, excelPath); for (String header : headers) { inputMap.put(header, new ArrayList<>()); } // 使用try-with-resources自动关闭资源 try (FileInputStream file = new FileInputStream(excelPath); XSSFWorkbook workbook = new XSSFWorkbook(file)) { int numberOfSheets = workbook.getNumberOfSheets(); for (int i = 0; i < numberOfSheets; i++) { if (workbook.getSheetName(i).equalsIgnoreCase("Sheet1")) { XSSFSheet sheet = workbook.getSheetAt(i); DataFormatter formatter = new DataFormatter(); // 遍历所有行,跳过表头行(行号0) for (Row row : sheet) { if (row.getRowNum() == 0) { continue; } // 遍历每个表头对应的列索引,处理单元格值 for (int colIndex = 0; colIndex < headers.size(); colIndex++) { String header = headers.get(colIndex); List<String> columnValues = inputMap.get(header); if (columnValues == null) { continue; } // 格式化单元格值,空值转为null String cellValue = formatter.formatCellValue(row.getCell(colIndex)); columnValues.add(cellValue.isEmpty() ? null : cellValue); } } break; // 找到Sheet1后无需继续遍历其他工作表 } } } return inputMap; } }
关键优化点说明
- 移除硬编码:不再手动定义values1到values8,而是根据表头动态生成List,支持任意列数
- 提升效率:原代码中每个表头都重新遍历一次所有行,优化后只遍历一次行,处理所有列,减少IO操作次数
- 资源安全:使用try-with-resources自动关闭
FileInputStream和XSSFWorkbook,避免资源泄漏 - 逻辑统一:所有列的处理逻辑复用同一套代码,后续新增列无需修改代码,只需确保表头正确即可
验证结果
运行优化后的代码,输出结果与预期完全一致:
{Column1=[C1,C2,C3], Column2=[C2,C3,C4], Column3=[4,56,3], Column4=[C4,C5,C6], Column5=[C5,C6,C7], Column6=[4,7,9], Column7=[C7,C8,C9], Column8=[5,5,6]}
内容的提问来源于stack exchange,提问作者Nvr
相关产品推荐
相关产品推荐

