You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TreeMap、Comparator与性能问题:带Comparator的TreeMap初始化耗时过长

为什么带Comparator的TreeMap初始化耗时远超自然排序版本?

嗨,这个现象我之前排查过,确实容易让人摸不着头脑——明明逻辑上都是用自然排序,怎么带Comparator的版本初始化慢这么多?先把你的测试代码补全(应该是截断了),方便大家理解场景:

public static void main(String[] args) {
    // 测试自然排序TreeMap初始化
    final long millis1 = System.currentTimeMillis();
    final TreeMap<Integer,Integer> natural = new TreeMap<>();
    final long millis2 = System.currentTimeMillis();
    System.out.println("自然排序TreeMap初始化耗时: " + (millis2 - millis1) + "ms");

    // 测试带Comparator的TreeMap初始化
    final long millis3 = System.currentTimeMillis();
    final TreeMap<Integer,Integer> withComparator = new TreeMap<>(Comparator.naturalOrder());
    final long millis4 = System.currentTimeMillis();
    System.out.println("带Comparator的TreeMap初始化耗时: " + (millis4 - millis3) + "ms");
}

核心原因:延迟加载的类初始化开销

其实问题根本不在TreeMap本身,而是类加载机制在搞事情:

  • 自然排序的TreeMap依赖的是Comparable接口,这是JDK启动时就会加载的核心类,早就完成了初始化,所以创建TreeMap时几乎没有额外开销
  • 而Comparator.naturalOrder()返回的是java.util.Comparator$NaturalOrderComparator——这是一个静态内部类,第一次调用naturalOrder()时才会触发它的类加载、验证、初始化流程,包括静态字段的赋值、类构造器执行等,这些额外的耗时全被算在了TreeMap的初始化时间里

验证方法:提前触发类加载

你可以试试把Comparator的调用放在测试最前面,提前支付类加载的开销:

public static void main(String[] args) {
    // 提前加载NaturalOrderComparator类
    Comparator.naturalOrder();

    // 再执行测试
    final long millis1 = System.currentTimeMillis();
    final TreeMap<Integer,Integer> natural = new TreeMap<>();
    final long millis2 = System.currentTimeMillis();
    System.out.println("自然排序TreeMap初始化耗时: " + (millis2 - millis1) + "ms");

    final long millis3 = System.currentTimeMillis();
    final TreeMap<Integer,Integer> withComparator = new TreeMap<>(Comparator.naturalOrder());
    final long millis4 = System.currentTimeMillis();
    System.out.println("带Comparator的TreeMap初始化耗时: " + (millis4 - millis3) + "ms");
}

这时候你会发现两次初始化的耗时几乎一致,因为类加载的开销已经提前完成了。

额外提醒:微基准测试要严谨

用System.currentTimeMillis()做单次测试其实不太严谨,容易受到JVM预热、GC等因素影响。如果要做准确的性能对比,建议用JMH(Java Microbenchmark Harness)来编写测试,它会自动处理预热、多次迭代统计等问题,结果更可靠。

另外,这种初始化耗时的差异只会出现在第一次创建带该Comparator的TreeMap时,后续创建实例时因为类已经加载完成,耗时就会和自然排序版本差不多了。如果业务中需要多次创建这类TreeMap,建议提前初始化一个Comparator实例复用,避免每次都触发类加载的开销。

内容的提问来源于stack exchange,提问作者Priv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 03:58:30