将CompareToBuilder替换为Java 8的Comperator.comparing(...)。thenComparing(...)

时间:2016-07-04 02:02:16

标签: intellij-idea java-8 comparator apache-commons-lang apache-commons-lang3

在Java 8之前,我们实现了Comparable.compareTo(...),如下所示:

public int compare(Person a, Person b) {
    return new CompareToBuilder()
            .append(a.getLastName(), b.getLastName())
            .append(a.getFirstName(), b.getFirstName())
            .toComparison();
}

从Java 8开始,我们可以这样做:

public int compare(Person a, Person b) {
    return Comparator
            .comparing(Person::getLastName)
            .thenComparing(Person::getFirstName)
            .compare(a, b);
}

新的Java 8方式可能允许我们删除commons-lang3依赖项。 新的Java 8更快吗?有没有办法自动迁移?我没有找到IntelliJ的意图。

请注意,当存在逆序并且涉及非自然比较时,它会变得有点复杂:

public int compare(SingleBenchmarkResult a, SingleBenchmarkResult b) {
    return new CompareToBuilder()
            .append(b.hasAnyFailure(), a.hasAnyFailure()) // Reverse
            .append(a.getAverageScore(), b.getAverageScore(), resilientScoreComparator)
            .toComparison();
}

变为

public int compare(SingleBenchmarkResult a, SingleBenchmarkResult b) {
    return Comparator
            .comparing(SingleBenchmarkResult::hasAnyFailure, Comparator.reverseOrder()) // Reverse
            .thenComparing(SingleBenchmarkResult::getAverageScore, resilientScoreComparator)
            .compare(a, b);
}

2 个答案:

答案 0 :(得分:8)

如果你这样写的话

public int compare(Person a, Person b) {
    return Comparator
            .comparing(Person::getLastName)
            .thenComparing(Person::getFirstName)
            .compare(a, b);
}

您通过为每次比较构建新的Comparator来浪费性能。在查看周围的代码时,它显然是荒谬的。 compare(Person a, Person b)方法肯定是实现Comparator<Person>的类的一部分,您可以在某个地方实例化以获得所需的比较器。您应该用唯一的Comparator.comparing(Person::getLastName).thenComparing(Person::getFirstName)实例替换那个实例,并在整个操作过程中使用。

E.g。

// reusable
static final Comparator<Person> By_NAME = Comparator
             .comparing(Person::getLastName).thenComparing(Person::getFirstName);

或临时

listOfPersons.sort(Comparator.comparing(Person::getLastName)
                             .thenComparing(Person::getFirstName));

如果你这样使用它,它很可能会更快。但是,您应该看到,没有简单的基于模式的替换可能。您必须使用该简单声明性构造替换该类的使用站点,并决定是将多个使用站点使用共享比较器实例还是ad-hoc创建它。然后,您可以删除整个旧的实现类,或者至少从它中删除比较器功能,如果它仍然用于其他目的。

答案 1 :(得分:2)

我认为没有任何预先定义的检查。您可能会尝试使用IntelliJ的structural-search,尽管我认为对于每种可能的情况都可能非常棘手。对于具有两个比较的简单情况的一种可能性可能如下:

搜索模板(出现次数$TYPE$$z$为2):

$ReturnType$ $MethodName$($TYPE$ $z$) {
        return new CompareToBuilder()
                .append($A$.$m$(), $B$.$m$())
                .append($A$.$m1$(), $B$.$m1$())
                .toComparison();
    }

替换模板:

$ReturnType$ $MethodName$($TYPE$ $z$) {
    return java.util.Comparator
            .comparing($TYPE$::$m$)
            .thenComparing($TYPE$::$m1$)
            .compare($A$, $B$);
}

我不是结构搜索的专家,但我想你必须为或多或少比较的电话制作另一种模式。