用Java 8的Comparator替换CompareToBuilder.comparing(...)。thenComparing(...)

问题描述 投票:8回答:2

在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);
}
intellij-idea java-8 comparator apache-commons-lang apache-commons-lang3
2个回答
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)实例代替that实例,在整个操作过程中都使用它。

例如

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

或临时

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

如果您以这种方式使用,则很有可能会更快。但是,您应该看到,不可能进行基于模式的简单替换。您必须用该简单的声明性结构替换类的使用站点,并决定是将共享的比较器实例用于多个使用站点还是临时创建。然后,您可以删除整个旧的实现类,或者至少可以从中删除比较器功能(如果它仍然有其他用途)。


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$);
}

我不是结构搜索专家,但是我想您将不得不为具有更多比较或更少比较的呼叫建立另一个模式。

© www.soinside.com 2019 - 2024. All rights reserved.