本文旨在解决java `treemap`对字符串类型键进行非标准排序的问题,特别是当字符串代表数字时,如何实现按数值大小进行降序排列。我们将详细介绍如何通过为 `treemap` 提供自定义 `comparator` 来覆盖其默认的字典序排序行为,从而实现将字符串键解析为长整型并进行数值比较,最终达到预期的降序排列效果。
TreeMap 是 Java 集合框架中一个基于红黑树实现的 Map 接口,它能够保持键的有序性。默认情况下,TreeMap 会根据键的自然顺序(如果键实现了 Comparable 接口)进行排序,或者根据在构造 TreeMap 时提供的 Comparator 进行排序。对于 String 类型的键,其自然顺序是字典序(lexicographical order)。
这意味着,当 String 键被 TreeMap 存储时,它们会按照字符的 Unicode 值进行逐位比较。例如,"5903766131" 会被认为小于 "59037662",因为在第三位字符 '0' 和 '3' 的比较中,'0' 小于 '3'。这与我们期望的数值大小排序(即 "59037662" 小于 "5903766131")是相悖的。
考虑以下示例代码,它展示了 TreeMap 默认的字符串键排序行为:
import java.util.Map;
import java.util.TreeMap;
public class ApplicationMain {
public
static void main(String[] args) {
final Map sampleTreeMap = new TreeMap<>();
sampleTreeMap.put("5903766131", 6);
sampleTreeMap.put("5903767", 7);
sampleTreeMap.put("590376614", 5);
sampleTreeMap.put("5903766170", 9);
sampleTreeMap.put("59037662", 12);
sampleTreeMap.put("5903766410", 10);
System.out.println("--- TreeMap 默认排序结果 ---");
sampleTreeMap.entrySet().stream().forEach(entry -> {
System.out.println("Key : " + entry.getKey() + " -- Value : " + entry.getValue());
});
}
} 上述代码的输出将是:
--- TreeMap 默认排序结果 --- Key : 5903766131 -- Value : 6 Key : 590376614 -- Value : 5 Key : 5903766170 -- Value : 9 Key : 59037662 -- Value : 12 Key : 5903766410 -- Value : 10 Key : 5903767 -- Value : 7
可以看到,"5903766131" 排在了 "59037662" 之前,这显然不是按数值大小排序的结果。
为了实现将 String 类型的键按照其代表的数值大小进行降序排列,我们需要在 TreeMap 构造时提供一个自定义的 Comparator。这个 Comparator 的核心逻辑是将 String 键解析为数值类型(例如 Long),然后基于这些数值进行比较。
以下是实现这一目标的修改方案:
import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;
public class ApplicationMain {
public static void main(String[] args) {
// 创建 TreeMap 时提供自定义 Comparator
// Comparator.comparingLong 将 String 转换为 Long 进行比较
// .reversed() 将默认的升序比较结果反转为降序
final Map sampleTreeMap =
new TreeMap<>(Comparator.comparingLong((String s) -> Long.parseLong(s)).reversed());
sampleTreeMap.put("5903766131", 6);
sampleTreeMap.put("5903767", 7);
sampleTreeMap.put("590376614", 5);
sampleTreeMap.put("5903766170", 9);
sampleTreeMap.put("59037662", 12);
sampleTreeMap.put("5903766410", 10);
System.out.println("\n--- TreeMap 自定义数值降序排序结果 ---");
sampleTreeMap.entrySet().stream().forEach(entry -> {
System.out.println("Key : " + entry.getKey() + " -- Value : " + entry.getValue());
});
}
} 修改后的代码将产生以下输出:
--- TreeMap 自定义数值降序排序结果 --- Key : 5903766410 -- Value : 10 Key : 5903766170 -- Value : 9 Key : 5903766131 -- Value : 6 Key : 590376614 -- Value : 5 Key : 59037662 -- Value : 12 Key : 5903767 -- Value : 7
可以看到,键已按照其数值大小进行了降序排列,这正是我们期望的结果。
让我们深入理解 new TreeMap(Comparator.comparingLong((String s) -> Long.parseLong(s)).reversed()); 这行代码:
因此,这个组合 Comparator 首先将 String 键转换为 long 类型进行数值比较,然后将比较结果反转,使得较大的数值排在前面。
TreeMap 是一个功能强大的有序映射,但其默认的 String 键排序是字典序。当需要对 String 键进行非标准的数值排序时,通过提供自定义 Comparator 是最灵活和推荐的方法。利用 Comparator.comparingLong() 结合 Lambda 表达式进行类型转换,并使用 .reversed() 实现降序,可以优雅地解决此类问题。理解 TreeMap 的工作原理和 Comparator 的灵活运用,是有效利用 Java 集合框架的关键。