导航
电话
咨询
地图
顶部
在java中,java.util.hashmap是一种常用的键值对存储结构。然而,hashmap的内部实现是基于哈希表,它不保证元素的迭代顺序。这意味着当你将excel表格中的列名和值存入hashmap时,即使你按照从左到右的顺序插入,hashmap在迭代时也可能以任意顺序返回这些键值对。这对于需要严格保持列顺序的场景(如将数据写回excel或按原顺序处理数据)来说,是一个显著的问题。
例如,一个Excel表格的列顺序是 column1, column2:
column1 column2 value1 value2 value3 value4
如果使用HashMap存储,得到的Map可能呈现如下无序状态:
0 = "column2" -> value2 "column1" -> value1 1 = "column2" -> value4 "column1" -> value3
这与我们期望的 column1 -> value1, column2 -> value2 的顺序不符。
为了解决HashMap的无序性问题,Java提供了java.util.LinkedHashMap。LinkedHashMap继承自HashMap,并额外维护了一个双向链表,用于记录元素的插入顺序。因此,当你遍历LinkedHashMap时,它会按照键值对被插入的顺序返回它们。这正是我们读取Excel数据并希望保持列顺序所需的特性。
以下是修改后的readExcelSheet方法,它将HashMap替换为LinkedHashMap,以确保列的顺序得到保留。
import org.apache.poi.ss.usermodel.*; import java.util.*; public class ExcelReaderUtil { /** * 从Excel工作表中读取数据,并以有序的List>形式返回。 * 每个Map代表一行数据,Map中的键值对顺序与Excel列的插入顺序一致。 * * @param sheet 要读取的Excel工作表对象 * @return 包含Excel数据的List,如果工作表为空则返回空列表 */ public static List> readExcelSheet(Sheet sheet) { // 获取行的迭代器 Iterator rows = sheet.iterator(); // 如果没有行,则返回空列表 if (!rows.hasNext()) { return Collections.emptyList(); } // 读取表头(第一行)作为Map的键 Row header = rows.next(); List keys = new ArrayList<>(); // 遍历表头单元格,获取列名 for (Cell cell : header) { String value = getCellValueAsString(cell); // 使用辅助方法获取单元格值 if (!value.isEmpty()) { keys.add(value); } else { // 遇到空列名时,可以根据实际需求选择跳出或继续 // 这里选择跳出,认为后续列可能不再是有效表头 break; } } // 初始化结果列表 List> result = new ArrayList<>(); // 遍历剩余的每一行数据 while (rows.hasNext()) { Row row = rows.next(); // 使用LinkedHashMap来保证列的插入顺序 Map rowMap = new LinkedHashMap<>(); // 遍历表头键,按顺序填充当前行的数据 for (int i = 0; i < keys.size(); ++i) { // 获取单元格,如果不存在则创建为空白单元格 Cell cell = row.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); String value = getCellValueAsString(cell); // 使用辅助方法获取单元格值 rowMap.put(keys.get(i), value); } // 只有当行不为空时才添加到结果列表 // 判断行是否为空:检查Map中所有值是否都为空字符串 if (!rowMap.values().stream().allMatch(String::isEmpty)) { result.add(rowMap); } } return result; } /** * 辅助方法:安全地获取单元格的字符串值,处理不同类型的单元格。 * * @param cell 单元格对象 * @return 单元格的字符串表示,如果单元格为null或空白,则返回空字符串 */ private static String getCellValueAsString(Cell cell) { if (cell == null) { return ""; } switch (cell.getCellType()) { case STRING: return cell.getStringCellValue(); case NUMERIC: // 对于日期类型,需要额外处理,这里简化为数值 if (DateUtil.isCellDateFormatted(cell)) { return cell.getDateCellValue().toString(); // 或者格式化为特定日期字符串 } else { return String.valueOf(cell.getNumericCellValue()); } case BOOLEAN: return String.valueOf(cell.getBooleanCellValue()); case FORMULA: // 对于公式单元格,可以尝试获取计算后的值 try { return String.valueOf(cell.getNumericCellValue()); // 尝试获取数值结果 } catch (IllegalStateException e) { try { return cell.getStringCellValue(); // 尝试获取字符串结果 } catch (IllegalStateException ex) { return ""; // 无法获取值 } } case BLANK: return ""; default: return ""; // 默认返回空字符串 } } // 示例用法 (需要Apache POI库) public static void main(String[] args) throws Exception { // 假设有一个名为 "example.xlsx" 的Excel文件 // 创建一个模拟的Workbook和Sheet用于测试 Workbook workbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook(); Sheet sheet = workbook.createSheet("Sheet1"); // 创建表头 Row headerRow = sheet.createRow(0); headerRow.createCell(0).setCellValue("column1"); headerRow.createCell(1).setCellValue("column2"); headerRow.createCell(2).setCellValue("column3"); // 增加一列测试 // 创建数据行1 Row dataRow1 = sheet.createRow(1); dataRow1.createCell(0).setCellValue("value1"); dataRow1.createCell(1).setCellValue("value2"); dataRow1.createCell(2).setCellValue(123); // 测试数值类型 // 创建数据行2 Row dataRow2 = sheet.createRow(2); dataRow2.createCell(0).setCellValue("value3"); dataRow2.createCell(1).setCellValue("value4"); dataRow2.createCell(2).setCellValue(true); // 测试布尔类型 // 创建空行(应被过滤) sheet.createRow(3); // 调用读取方法 List> data = readExcelSheet(sheet); // 打印结果,观察列顺序 for (Map rowMap : data) { System.out.println("--- Row ---"); rowMap.forEach((key, value) -> System.out.println(" " + key + " -> " + value)); } workbook.close(); } }
代码改进说明:
除了LinkedHashMap,Java还提供了其他Map实现,它们在特定场景下也可能有用:
org.apache.poi poi 5.2.3 org.apache.poi poi-ooxml 5.2.3
通过将HashMap替换为LinkedHashMap,可以有效地解决在Java中读取Excel数据时列顺序混乱的问题,确保数据在内存中保持与源文件一致的结构,从而简化后续的数据处理和回写操作。
# ai # switch # if # 接口 # 是一个 # excel # 如果你 # 继承 # Java # String # 字符串 # 为空 # 键值对 # map # 空字符串 # 迭代 # 键值 # 遍历 # excel表格 # break # 它会 # apache # 数据处理 # 单元格 # 字符串类型 # gradle # maven
相关栏目: 【 行业资讯 】 【 网络运营 】 【 GEO优化 】 【 营销推广 】 【 SEO优化 】 【 技术教程 】 【 代码知识 】 【 AI推广 】
相关推荐: php高频调试功能有哪些_php常用调试函数与工具汇总【解答】 Mac的访达(Finder)怎么用_Mac文件管理入门教程【详解】 如何在Golang中优化文件读写性能_使用缓冲和并发处理 Python大型项目拆分策略_模块化解析【教程】 Win10系统怎么查看网络连接状态_Windows10网络和共享中心 Win11怎么关闭建议的内容_Windows11系统通知取消建议设置 VSC怎么在PHP中调试MySQL_数据库交互排查技巧【教程】 php485支持哪些操作系统_php485跨系统支持情况介绍【解答】 如何在Golang中指定模块版本_使用go.mod控制版本号 Win11怎么设置默认邮件应用_Windows11应用关联Mail设置 c++如何使用std::bind绑定函数参数_c++ 占位符std::placeholders使用【详解】 Windows 11怎么设置默认解压软件_Windows 11为ZIP/RAR文件指定默认打开程序 如何使用Golang实现路由分组管理_Golang路由分组与权限控制方法 Win11怎么开启自动HDR画质_Windows11显示设置HDR选项 Win11怎么设置DNS服务器_Windows11修改网络适配器DNS优选 php在Linux怎么部署_LNMP环境搭建PHP服务的详细指南【指南】 C++如何解析JSON数据?(nlohmann/json库示例) php订单日志怎么记录发货_php记录订单发货操作日志指南【指南】 mac怎么看硬盘大小_MAC查看磁盘存储空间与文件占用【详解】 Golang如何实现基本的用户注册_Golang用户注册表单处理示例 如何高效获取循环末次生成的 NumPy 数组最后一个元素(无需额外循环) 如何在Golang中使用replace替换模块_指定本地或远程路径 Win10 BitLocker加密教程 Win10给磁盘驱动器上锁【安全】 获取 PHP 文件最后修改时间的正确方法 如何在Golang中引入测试模块_Golang测试包导入与使用实践 如何在Golang中实现服务熔断与限流_Golang微服务容错与流控方法 如何使用Golang实现文件追加操作_向已有文件追加数据 Win11如何连接Xbox手柄 Win11蓝牙连接游戏手柄教程【步骤】 Windows任务计划服务异常原因_任务调度失败的处理方案 Win11 explorer.exe频繁崩溃_修复Win11资源管理器无限重启【步骤】 如何使用Golang反射将map转换为struct_Golang reflect类型映射技巧 php命令行怎么运行_通过CLI模式执行PHP脚本的步骤【说明】 Win10怎么更改用户名 Win10修改账户名称操作教程 如何在Windows上设置闹钟和计时器_系统自带的时钟应用全攻略【生活技巧】 Win11怎么关闭应用权限_Windows11相机麦克风隐私管理 Windows电脑如何截屏?(四种快捷方法) Windows笔记本无法进入睡眠模式怎么办?(电源疑难解答) 如何在Golang中配置代码格式化工具_使用gofmt和goimports 如何使用Golang安装API文档生成工具_快速生成接口文档 php8.4如何调用com组件_php8.4windows下com操作指南【教程】 Windows10系统怎么查看硬盘健康_Win10 SMART信息检测工具 如何使用Golang template生成文本模板_动态生成HTML或文本 Win11怎么关闭系统声音_Win11系统提示音静音设置【详解】 Win11怎么开启远程桌面连接_Windows11系统属性远程设置 Windows11如何开启虚拟桌面_Windows11虚拟桌面使用攻略【技巧】 如何使用Golang包导出规则_控制函数和变量可见性 Win11如何隐藏桌面图标 Win11一键隐藏/显示桌面图标【指南】 Win11任务栏天气怎么关闭 Win11隐藏天气小组件图标【设置】 如何在 Go 中正确测试带 Cookie 的 HTTP 请求 Win11如何设置自动关机 Win11定时关机命令使用教程【技巧】
赣ICP备2024031479号