
本文介绍如何对形如 "1D"、"23M" 的字符串列表进行自定义排序:先按末尾字母升序排列,再在相同字母组内按前面数字升序排列。使用 Java 8+ 的 Comparator.comparing 链式方法可简洁、安全、高效地实现该逻辑。
本文介绍如何对形如 "1d"、"23m" 的字符串列表进行自定义排序:先按末尾字母升序排列,再在相同字母组内按前面数字升序排列。使用 java 8+ 的 `comparator.comparing` 链式方法可简洁、安全、高效地实现该逻辑。
要正确排序类似 (2D, 1D, 1Y, 23M, 4M, 2Y, 12D) 的字符串列表,并得到期望结果 (1D, 2D, 12D, 4M, 23M, 1Y, 2Y),关键在于理解排序规则的两层优先级:
-
第一优先级:按字符串末尾的字母(如
'D','M','Y')字典序升序; -
第二优先级:在字母相同的情况下,将前面的数字部分(如
"1","12","23")解析为整数后升序排列。
原始代码失败的主要原因有三:
-
s.split("")将字符串拆分为单字符数组,[1]取第二个字符——但"1D"长度为 2,索引1是'D',而"23M"长度为 3,索引1是'3',逻辑错乱; - 未校验字符串格式,
Integer.parseInt在非数字前缀时会抛出NumberFormatException; - 未处理空字符串或长度不足的异常边界情况。
✅ 推荐写法(Java 8+,简洁且健壮):
myList.sort(
Comparator.comparing((String s) -> s.charAt(s.length() - 1))
.thenComparingInt(s -> Integer.parseInt(s.substring(0, s.length() - 1)))
);
该写法利用函数式接口链式组合:
-
comparing(...)提取并比较末尾字符(自动按char的 Unicode 值排序,等价于字母序); -
thenComparingInt(...)在首级相同时,提取前n−1个字符并转为int进行数值比较(避免字符串字典序误判"12D""4M" 的问题)。
⚠️ 注意事项:
- 确保所有字符串非空、长度 ≥ 2,且末尾为字母、前面部分可转为有效整数;否则需添加预处理或异常处理。生产环境建议封装为安全版本:
myList.sort((s1, s2) -> {
if (s1 == null || s2 == null || s1.length() <p>总结:合理利用 <code>Comparator</code> 的组合能力,结合明确的提取逻辑(<code>charAt(length-1)</code> + <code>substring(0, length-1)</code>),即可优雅实现“字母后缀优先、数字前缀次之”的双级排序,既避免手动类型转换错误,又提升代码可读性与可维护性。</p>










