
本文介绍如何使用 Java 8 的 Stream API 和传统循环两种方式,将形如 "20232,20221,..." 的年月编码字符串解析为 Map<String, String>,其中 key 为 4 位年份,value 为去重、升序、逗号分隔的月份字符串。
本文介绍如何使用 java 8 的 stream api 和传统循环两种方式,将形如 `"20232,20221,..."` 的年月编码字符串解析为 `map
在 Java 应用中,常需处理紧凑编码的时间字符串(如 "20232" 表示 2023 年 2 月)。本教程提供两种健壮、可读性强的实现方案:一种是函数式风格的 Stream + Collectors 组合,另一种是清晰易懂的传统迭代方式。两者均确保:
✅ 年份提取准确(前 4 位字符)
✅ 月份提取鲁棒(剩余部分自动转为 Integer,兼容 10/11/12 等多位数)
✅ 同一年份下的月份自动去重、升序排列
✅ 最终 value 为逗号分隔的标准字符串(无尾随逗号)
✅ 推荐方案:Stream API(简洁高效)
String str = "20232,20221,20222,20223,20224,20225,20226,20227,20228,20229,202210,202211,202212,20231";
// 步骤 1:按年分组,值为 TreeSet<Integer>(天然升序+去重)
Map<String, Set<Integer>> yearToMonths = Arrays.stream(str.split(","))
.collect(Collectors.groupingBy(
s -> s.substring(0, 4), // key: 年份(String)
Collectors.mapping(
s -> Integer.parseInt(s.substring(4)), // 提取并转为 Integer
Collectors.toCollection(TreeSet::new) // 自动升序、去重
)
));
// 步骤 2:转换为最终 Map<String, String>
Map<String, String> result = yearToMonths.entrySet().stream()
.collect(Collectors.toMap(
Map.Entry::getKey,
e -> e.getValue().stream()
.map(String::valueOf)
.collect(Collectors.joining(","))
));
// 输出结果
result.forEach((year, months) ->
System.out.println("[Key] : " + year + " [Value] : " + months));输出:
[Key] : 2023 [Value] : 1,2 [Key] : 2022 [Value] : 1,2,3,4,5,6,7,8,9,10,11,12
✅ 兼容方案:传统 for 循环(适合初学者)
Map<String, Set<Integer>> yearToMonths = new HashMap<>();
Map<String, String> result = new HashMap<>();
String[] parts = str.split(",");
for (String part : parts) {
String year = part.substring(0, 4);
int month = Integer.parseInt(part.substring(4)); // 自动处理 "10"/"12" 等
yearToMonths.computeIfAbsent(year, k -> new TreeSet<>()).add(month);
}
// 构建最终字符串值
for (Map.Entry<String, Set<Integer>> entry : yearToMonths.entrySet()) {
StringJoiner joiner = new StringJoiner(",");
for (int month : entry.getValue()) {
joiner.add(String.valueOf(month));
}
result.put(entry.getKey(), joiner.toString());
}? 关键技巧说明:
- 使用 computeIfAbsent 替代手动 containsKey 判断,代码更简洁;
- StringJoiner 比 StringBuilder 更安全——无需手动处理分隔符边界;
- TreeSet 保证插入即排序,避免后续调用 Collections.sort()。
⚠️ 注意事项
- 输入校验:生产环境建议添加 null 或空字符串检查,以及 substring 越界防护(例如 part.length() < 4 时跳过或抛异常);
- 性能考量:对于超大数据量(>10 万项),Stream 方案因对象创建略高开销,但可读性与维护性优势显著;
- 扩展性:若需支持 ISO 格式(如 "2023-02"),只需调整 substring 逻辑为正则匹配或 DateTimeFormatter 解析。
通过以上任一方案,你都能高效、准确地完成年月字符串到结构化 Map 的转换,为后续统计、筛选或前端展示提供坚实的数据基础。


















