方法链如何在Java 8 Comparator中工作?

Ces*_*sar 9 java java-8 ocpjp

我正在准备Java 8证书,以下让我困惑一点点,也许有人可以帮我这个?在该示例中,对Squirrel类进行了建模.它有名字和重量.现在你可以创建一个Comparator类来使用这两个字段对这个东西进行排序.所以首先按名称排序,然后按重量排序.像这样的东西:

public class ChainingComparator implements Comparator<Squirrel> {
    public int compare(Squirrel s1, Squirrel s2) {

        Comparator<Squirrel> c = Comparator.comparing(s -> s.getSpecies());
        c = c.thenComparingInt(s -> s.getWeight());

        return c.compare(s1, s2);
    }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止一切都那么好..但后来令人费解的部分.在代码示例下面,他们声明您可以使用方法链接在一行中编写它.也许我误解了,但当我链接比较thenComparing部分时,我得到一个编译错误.它与被比较的对象类型有关(首先是String,然后是int).

当我输入中间变量而不是链接时,为什么它可以工作?是否有可能连锁?

dav*_*xxx 8

当你链接两者时,编译器无法推断返回的比较器的类型参数,comparing()因为它依赖于返回的比较器thenComparingInt()本身无法推断.

在lambda参数中指定类型comparing()(或使用方法引用),它解决了推理问题,因为comparing()可以推断出返回的类型.:

    Comparator<Squirrel> c = Comparator.comparing((Squirrel s)  -> s.getSpecies())
                                       .thenComparingInt(s -> s.getWeight());
Run Code Online (Sandbox Code Playgroud)

请注意,在lambda参数中指定类型thenComparingInt()(或使用方法引用),例如:

    Comparator<Squirrel> c = Comparator.comparing(s -> s.getSpecies())
                                       .thenComparingInt((Squirrel s) -> s.getWeight());
Run Code Online (Sandbox Code Playgroud)

在推理类型计算中不考虑接收器(这里是链接方法的返回类型).

这篇JDK 8教程/文档很好地解释了这一点:

注意:重要的是要注意推理算法仅使用调用参数,目标类型,并且可能使用明显的预期返回类型来推断类型.推理算法不使用程序中稍后的结果.


Ole*_*hov 5

是的,这是可能的-链comparing(...)thenComparing(...),并与compare(...)使用方法引用的,而不是lambda表达式:

public int compare(Squirrel s1, Squirrel s2) {
    return Comparator.comparing(Squirrel::getSpecies)
        .thenComparing(Squirrel::getWeight)
        .compare(s1, s2);
}
Run Code Online (Sandbox Code Playgroud)

为什么这样工作?在回答类似问题时,我无法比布莱恩更好地解释它.

此外,这可以用1行重写(假设您有一个要排序的松鼠列表):

list.sort(Comparator.comparing(Squirrel::getSpecies).thenComparing(Squirrel::getWeight));
Run Code Online (Sandbox Code Playgroud)