
在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数据并希望保持列顺序所需的特性。
立即学习“Java免费学习笔记(深入)”;
以下是修改后的readExcelSheet方法,它将HashMap替换为LinkedHashMap,以确保列的顺序得到保留。
import org.apache.poi.ss.usermodel.*;
import java.util.*;
public class ExcelReaderUtil {
/**
* 从Excel工作表中读取数据,并以有序的List<Map<String, String>>形式返回。
* 每个Map代表一行数据,Map中的键值对顺序与Excel列的插入顺序一致。
*
* @param sheet 要读取的Excel工作表对象
* @return 包含Excel数据的List,如果工作表为空则返回空列表
*/
public static List<Map<String, String>> readExcelSheet(Sheet sheet) {
// 获取行的迭代器
Iterator<Row> rows = sheet.iterator();
// 如果没有行,则返回空列表
if (!rows.hasNext()) {
return Collections.emptyList();
}
// 读取表头(第一行)作为Map的键
Row header = rows.next();
List<String> keys = new ArrayList<>();
// 遍历表头单元格,获取列名
for (Cell cell : header) {
String value = getCellValueAsString(cell); // 使用辅助方法获取单元格值
if (!value.isEmpty()) {
keys.add(value);
} else {
// 遇到空列名时,可以根据实际需求选择跳出或继续
// 这里选择跳出,认为后续列可能不再是有效表头
break;
}
}
// 初始化结果列表
List<Map<String, String>> result = new ArrayList<>();
// 遍历剩余的每一行数据
while (rows.hasNext()) {
Row row = rows.next();
// 使用LinkedHashMap来保证列的插入顺序
Map<String, String> 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<Map<String, String>> data = readExcelSheet(sheet);
// 打印结果,观察列顺序
for (Map<String, String> rowMap : data) {
System.out.println("--- Row ---");
rowMap.forEach((key, value) -> System.out.println(" " + key + " -> " + value));
}
workbook.close();
}
}代码改进说明:
除了LinkedHashMap,Java还提供了其他Map实现,它们在特定场景下也可能有用:
<!-- Maven -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.3</version> <!-- 使用最新稳定版本 -->
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.3</version> <!-- 处理.xlsx文件需要此依赖 -->
</dependency>通过将HashMap替换为LinkedHashMap,可以有效地解决在Java中读取Excel数据时列顺序混乱的问题,确保数据在内存中保持与源文件一致的结构,从而简化后续的数据处理和回写操作。
以上就是读取Excel数据并保持列顺序的Java实践的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号