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

Geo*_*met 8 intellij-idea comparator java-8 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();
}
Run Code Online (Sandbox Code Playgroud)

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

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

新的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();
}
Run Code Online (Sandbox Code Playgroud)

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

Hol*_*ger 8

如果你这样写的话

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

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

例如

// reusable
static final Comparator<Person> By_NAME = Comparator
             .comparing(Person::getLastName).thenComparing(Person::getFirstName);
Run Code Online (Sandbox Code Playgroud)

或临时的

listOfPersons.sort(Comparator.comparing(Person::getLastName)
                             .thenComparing(Person::getFirstName));
Run Code Online (Sandbox Code Playgroud)

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

  • 如果您实现自然顺序,则该方法应为“ compareTo(Person)”而不是“ compare(Person,Person)”,因此该问题具有误导性。我不认为使用`Comparator.comparing`会比`CompareToBuilder`慢,但是您仍然可以通过声明我的答案所示的`static final`字段并将`compareTo(Person)`实现为`返回BY_NAME.compare(this,other);`。 (2认同)

use*_*547 3

我认为没有任何预先定义的检查。您可能会尝试使用 IntelliJ 的结构搜索,尽管我认为针对每种可能的情况执行此操作可能相当棘手。具有两次比较的简单情况的一种可能性可能如下:

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

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

替换模板:

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

我不是结构搜索方面的专家,但我想您必须为具有或多或少比较的调用制定另一种模式。