当前位置:
当从Excel文件中读取数据并将其存储到List<Map>结构中时,标准的HashMap无法保证键值对的插入顺序,导致列顺序混乱。本教程将详细介绍如何利用LinkedHashMap来有效解决这一问题,确保数据在内存中保持与Excel源文件一致的列顺序,为后续的数据处理或写回Excel提供便利,并提供完整的Java代码示例。
在Java中,HashMap是一种基于哈希表的Map实现,它提供了高效的键值对存储和检索能力。然而,HashMap的设计初衷是为了优化性能,而不是为了维护元素的插入顺序。这意味着当你向HashMap中添加键值对时,它们在内部的存储顺序是不确定的,并且可能会随着哈希冲突的解决或内部扩容而改变。
对于Excel这类结构化数据源,列的顺序通常是固定的且具有业务意义。例如,一个Excel表格可能有“姓名”、“年龄”、“城市”三列,如果使用HashMap存储每一行数据,那么读取后,Map中键值对的顺序可能是“年龄”->“姓名”->“城市”,而非原始的“姓名”->“年龄”->“城市”。当需要将这些数据写回Excel或进行依赖列顺序的进一步处理时,这种顺序的丢失就会成为一个严重的问题。
为了解决HashMap不保留插入顺序的问题,Java提供了两种特殊的Map实现:
考虑到我们的目标是保留Excel中“从左到右”的原始列顺序,LinkedHashMap是最佳选择。
下面我们将修改原始代码,将每一行数据的存储容器从HashMap替换为LinkedHashMap,以确保列顺序的保留。
import org.apache.poi.ss.usermodel.*; import java.util.*; import java.util.stream.Collectors; public class ExcelDataReader { /** * 从Excel工作表中读取数据,并将其存储为List>。 * 每个Map代表一行数据,键为列标题,值为单元格内容。 * 使用LinkedHashMap确保列的顺序与Excel中一致。 * * @param sheet 要读取的Excel工作表对象。 * @return 包含所有行数据的List,每行数据是一个LinkedHashMap。 * 如果工作表为空,则返回一个空列表。 */ public static List> readExcelSheet(Sheet sheet) { Iterator rows = sheet.iterator(); // 检查工作表是否为空 if (!rows.hasNext()) { return Collections.emptyList(); } // 读取表头(第一行)以获取列名和它们的顺序 Row headerRow = rows.next(); List columnHeaders = new ArrayList<>(); // 遍历表头单元格,获取所有非空列名 for (Cell cell : headerRow) { String headerValue = cell.getStringCellValue().trim(); // 获取并清理列名 if (!headerValue.isEmpty()) { columnHeaders.add(headerValue); } else { // 如果遇到空列名,认为后续没有有效列,停止读取表头 // 实际应用中可能需要更复杂的逻辑来处理空列名或合并单元格 break; } } List> allRowsData = new ArrayList<>(); // 遍历剩余的行(数据行) while (rows.hasNext()) { Row dataRow = rows.next(); // 使用LinkedHashMap来保证列的插入顺序与表头一致 Map rowDataMap = new LinkedHashMap<>(); // 遍历已识别的列头,按顺序获取对应单元格的值 for (int i = 0; i < columnHeaders.size(); ++i) { String columnName = columnHeaders.get(i); // 获取单元格,如果单元格不存在则创建为空白单元格 Cell cell = dataRow.getCell(i, Row.MissingCellPolicy.CREATE_NULL_AS_BLANK); String cellValue = getCellValueAsString(cell); // 统一处理单元格值 rowDataMap.put(columnName, cellValue); } // 仅添加非空行到结果列表 // 判断行是否为空的逻辑:如果所有值都为空字符串,则认为是空行 if (!rowDataMap.values().stream().allMatch(String::isEmpty)) { allRowsData.add(rowDataMap); } } return allRowsData; } /** * 辅助方法:将单元格内容统一转换为字符串。 * 处理不同类型的单元格,避免toString()直接调用可能带来的问题。 * * @param cell 单元格对象。 * @return 单元格内容的字符串表示。 */ private static String getCellValueAsString(Cell cell) { if (cell == null) { return ""; } switch (cell.getCellType()) { case STRING: return cell.getStringCellValue().trim(); case NUMERIC: if (DateUtil.isCellDateFormatted(cell)) { // 处理日期类型 return cell.getDateCellValue().toString(); // 或者使用SimpleDateFormat格式化 } 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().trim(); // 假设公式结果为字符串 } catch (IllegalStateException ex) { return ""; // 无法获取结果 } } case BLANK: return ""; default: return cell.toString().trim(); // 其他类型直接转字符串 } } // 示例用法 public static void main(String[] args) { // 假设你有一个Excel文件 "example.xlsx" // 这里只是一个模拟,实际使用需要引入Apache POI库并加载Workbook // Workbook workbook = new XSSFWorkbook(new FileInputStream("example.xlsx")); // Sheet sheet = workbook.getSheetAt(0); // 为了演示,我们创建一个模拟的Sheet对象 // 在实际项目中,你需要使用Apache POI加载真实的Excel文件 // 以下代码仅为概念性演示,不能直接运行,需要POI库支持 // 假设 sheet 对象已经通过 Workbook.getSheetAt(0) 或其他方式获得 // 模拟一个简单的Excel工作表 Workbook mockWorkbook = new org.apache.poi.xssf.usermodel.XSSFWorkbook(); Sheet mockSheet = mockWorkbook.createSheet("SampleData"); // 创建表头 Row header = mockSheet.createRow(0); header.createCell(0).setCellValue("column1"); header.createCell(1).setCellValue("column2"); // 创建数据行1 Row row1 = mockSheet.createRow(1); row1.createCell(0).setCellValue("value1"); row1.createCell(1).setCellValue("value2"); // 创建数据行2 Row row2 = mockSheet.createRow(2); row2.createCell(0).setCellValue("value3"); row2.createCell(1).setCellValue("value4"); List> data = readExcelSheet(mockSheet); System.out.println("读取到的数据 (LinkedHashMap 保持顺序):"); for (int i = 0; i < data.size(); i++) { Map rowMap = data.get(i); System.out.println(i + " = " + rowMap); // 验证顺序 rowMap.forEach((key, value) -> System.out.println(" \"" + key + "\" -> " + value)); } // 预期输出: // 0 = {column1=value1, column2=value2} // "column1" -> value1 // "column2" -> value2 // 1 = {column1=value3, column2=value4} // "column1" -> value3 // "column2" -> value4 } }
代码解释:
org.apache.poi poi 5.2.3 org.apache.poi poi-ooxml 5.2.3
通过将存储每行数据的Map实现从HashMap替换为LinkedHashMap,我们可以轻松解决Java读取Excel数据时列顺序混乱的问题。LinkedHashMap能够完美地保留键值对的插入顺序,这对于依赖列顺序的Excel数据处理至关重要。结合对表头列名的有序提取和单元格内容的健壮处理,我们可以构建出高效且准确的Excel数据读取器,为后续的数据操作提供可靠的基础。
JM漫画app最新版入口是https://www.jmmanhua.top/,这里有免费观看、离线下载及极简操作优势。针对隐私保护需求,详细解析在设置中通过“隐私设置”与“我收藏的漫画”界面实现内容完全隐藏的具体步骤。同时解答新手关于操作流程、离线功能及适用性的常见疑问,帮助用户快速上手并享受无广告干扰的阅读体验。
面向希望获取丰富漫画资源并实现离线阅读的移动端用户,漫蛙3Manwa3(https://www.manwamh.top/)提供快速更新与多设备支持。针对网络不稳定或流量受限痛点,本文详解官方正版下载后的核心操作:包括通过详情页批量缓存章节、利用关键词与榜单精准检索韩漫、切换横竖屏及夜间模式优化体验,以及账号登录实现跨安卓设备进度同步,帮助用户高效管理本地资源库。
面向二次元漫画爱好者,漫蛙漫画(https://www.manwamh.top/)提供丰富的全彩漫画资源及多国语言阅读支持。针对用户寻找稳定入口、高效检索及舒适阅读的需求,本文介绍漫蛙漫画的线路选择、防走失网址收藏方法,详解从“最近更新”查找韩漫、一键搜索到离线下载的操作流程,并涵盖日间/夜间模式切换、书架管理等新手必备技巧,帮助用户快速上手享受流畅的追漫体验。
漫蛙Manwa3 APP最新版下载地址:https://www.manwamh.top/,这里包含核心功能与操作流程。针对账号注册、VIP开通及阅读设置等关键环节,本文详细梳理了从手机号注册登录、浏览热门榜单到开启高清无广告阅读的具体步骤。涵盖多语言切换、云同步、断点续传及多种阅读模式调整方法,帮助用户快速掌握软件用法,享受流畅的追漫体验。
iSlide设计工具侧边栏不见了怎么办?本教程详解在Windows版PPT中通过【设计工具】按钮恢复侧边栏的方法,涵盖面板拖拽、模块隐藏检查及插件加载异常的处理,同时提供macOS用户的使用指引。
全面盘点Flutter主流状态管理框架,深度解析Provider、Riverpod、Bloc与GetX的核心机制、优缺点及适用场景,提供系统化的状态管理选型指南。
新手入门 NetLimiter 必读指南。详解 Activity 实时监控、DL/UL Limit 限速设置、Blocker 阻止规则及 Stats 流量统计功能。图文结合展示规则编辑器操作,助你轻松管理 Windows 应用网络带宽。
在Linux系统中,复制文件并改名并没有单独的独立命令,而是通过标准复制命令cp在指定目标路径时直接写上新文件名来完成。本文详解cp命令复制并重命名的操作语法、同目录与跨目录示例、常用安全参数及目录复制实践。
学习如何将Blender中的动态材质导出为图片序列。涵盖输出路径设置、PNG格式选择、帧范围确认及Image Sequence贴图的重新载入方法,适合需要保留透明通道或后期处理的动画贴图工作流。
想在iPhone或iPad上实现锁屏一键直达?本文详解“锁屏启动”的安装前检查清单、系统权限配置步骤及小组件添加方法,解决组件不显示、点击无反应等常见问题,确保快捷指令、网页和App快速启动。
正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。
正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。
正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。
Postman是一套面向API全生命周期的开发与测试平台,可在Mac上发送和调试多种协议请求,管理集合、环境及认证信息,并完成脚本测试、模拟服务、监控、文档发布和团队协作。它适合开发、测试及运维人员使用,提供个人免费方案。
Docker Desktop 是 Docker 官方为 Mac 提供的容器开发环境,集成 Docker Engine、命令行工具、Compose、Build、Kubernetes 与图形化管理界面。
Android Studio 是 Google 面向安卓应用开发提供的官方集成开发环境,基于 IntelliJ IDEA 构建。它整合智能代码编辑、Gradle 构建、界面预览、设备模拟、性能分析、调试测试及 APK 分析等工具。
PixPix 是面向品牌、卖家和内容团队的在线 AI 图片视频创作平台,提供图视频 Agent、无限画布、图片生成、视频生成、自然语言编辑及商品套图、产品精修和带货视频等电商工具。
Postman 是面向 API 全生命周期的开发与协作平台。Windows 桌面版可用于构建和发送 HTTP、GraphQL、gRPC、WebSocket、MQTT 等请求,并提供环境变量、集合、脚本测试、模拟服务、监控、文档及团队工作区等
Docker Desktop 为 Windows 开发者提供集成式容器环境,内置 Docker Engine、命令行工具、Compose、Build 与 Kubernetes 等组件,可在本机完成镜像构建、容器运行、日志查看和资源管理。