Codeforces: 为什么Java中要避免使用Comparator类中的comparingX或thenComparingX

⚠️
背景是刷CF,所以最高优先级是代码效率,其次是敲代码的效率,最后才是可读。而对于工程化,我水平低,我认为用不到。

背景

假设要对一个数组排序,或者有一个TreeSet需要指定顺序。

这里以下面这个类为例:

class Node {
    int index, value;
 
    public Node(int index, int value) {
        this.index = index;
        this.value = value;
    }
}

定义一个这个类的TreeSet,将有下面两种写法

new TreeSet<>(Comparator.comparingInt((Node o) -> o.value).thenComparingInt(o -> o.index));
new TreeSet<>((o1, o2) -> o1.value != o2.value ? Integer.compare(o1.value, o2.value) : Integer.compare(o1.index, o2.index));

显然,第一种写法非常的美。但是,显然又很遗憾,第一种写法会慢……建议使用第二种写法。甚至第二种写法还是太慢了,直接o1.value - o2.value。甚至更考虑把两个int塞到一个long里进行比较。


原因

总而言之,工程化程度太高,各种检查太多,调用栈也太深了。

comparingX类的方法往往要求传入一个lambda函数,同时其源码往往包含null的检查。如果要thenComparingX的话,那这个调用栈就更深了。那么第一种写法的调用栈大概是:

treeSet -> comparator_2 -> comparator_1 -> lambda_1 -> lambda_2

反过来第二种写法在调用栈就比较简单

treeSet -> comparator

在必要的逻辑都一样的情况下,第一种写法会多出一堆调用。自然就慢了。


实战案例

原始版本:

Submission #225373575 - Codeforces
Codeforces. Programming competitions and contests, programming community
Time limit exceeded on test 12

优化了Comparator:

Submission #225390974 - Codeforces
Codeforces. Programming competitions and contests, programming community
Time limit exceeded on test 22

优化了IO和数组处理:

Submission #225392438 - Codeforces
Codeforces. Programming competitions and contests, programming community
Accepted
蜀ICP备19018968号