带有比较器的Java Lambda表达式

时间:2017-09-02 11:43:31

标签: java lambda java-8 comparator

以下用于对数组列表进行排序的代码有效:

    ArrayList<Edge> edges = g.edges();
    edges.sort((Comparator.comparingInt(Edge::getWeight)).thenComparing(e -> e.getU() + e.getV() + e.getWeight()));

在做同样的事情时,另一种方式会导致编译时错误

    ArrayList<Edge> edges = g.edges();
    edges.sort(Comparator.comparingInt(f -> f.getWeight()).thenComparing(e -> e.getU() + e.getV() + e.getWeight()));

g.edges()返回边数组列表。

为什么会发生这种情况,第一种方法有效,而第二种方法没有? edges.sort(Comparator.comparingInt(f -> f.getWeight())edges.sort(Comparator.comparingInt(Edge::getWeight))一样正常,但第一种方法不允许使用.thenComparing(\*lambda exp*\)而第二种方法允许使用static class Edge { int u; int v; int weight; int getU() { return u; } int getV() { return v; } int getWeight() { return weight; } Edge(int u, int v, int weight) { this.u = u; this.v = v; this.weight = weight; } } 。为什么会这样?

Edge类 -

list_data = [
    (237146768, u'43 S LUBEC RD', u'LUBEC', u'ME'),
    (455414678, u'PO BOX 41', u'LUBEC', u'ME')
]
context = {'list_data': list_data}
return render(request, 'templatename.html', context}

3 个答案:

答案 0 :(得分:1)

如果您阅读错误消息,您会得到一个线索:

Error:(13, 50) java: cannot find symbol
  symbol:   method getWeight()
  location: variable f of type java.lang.Object

所以看起来编译器有一个限制,通过像这样的方法链来推断类型参数。有多种方法可以为编译器提供一些提示:

import java.util.ArrayList;
import java.util.Comparator;

public class Edge {
    public int getWeight() {
        return 0;
    }
    public static void main(String[] args) throws InterruptedException {
        ArrayList<Edge> edges = null;

        // The following will work:
        edges.sort(Comparator.<Edge>comparingInt(f -> f.getWeight()).thenComparingInt(f -> f.getWeight()));
        edges.sort(Comparator.comparingInt((Edge f) -> f.getWeight()).thenComparingInt(f -> f.getWeight()));
        edges.sort(Comparator.comparingInt(Edge::getWeight).thenComparingInt(f -> f.getWeight()));
        edges.sort(Comparator.comparingInt(f -> f.getWeight()));

        //The following will not:
        edges.sort(Comparator.comparingInt(f -> f.getWeight()).thenComparingInt(f -> f.getWeight()));
    }
}

答案 1 :(得分:1)

这是<T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor)的定义。

您的第一行代码 -

Foo

Comparator.comparingInt(Edge::getWeight) 上实现功能界面ToIntFunction,在您的情况下 T 要比较的元素类型并返回Edge

进一步使用

在你的第二行代码中 -

Comparator<Edge>

Comparator.comparingInt(f -> f.getWeight()) 的类型未定义,因此编译将失败。相反,您可以将f的类型转换为Edge,这只会以类似的方式工作:

f

虽然现在编译器可能实际上开始建议用方法引用替换它,这与(1)相同。

注意 :为什么推断(Comparator.comparingInt((Edge f) -> f.getWeight())) 类型为f的推断在线程Generic type inference not working with method chaining?中解释

答案 2 :(得分:0)

在有效的解决方案中,编译器知道Edge::getWeight期望Edge,因此推断ToIntFunction<? super T>ToIntFunction<Edge>

但是,使用lambda,编译器无法推断出类型(因此,它不知道它是Edge并将其视为对象)。

快速解决方案是让编译器知道它是Edge:

edges.sort(Comparator.<Edge>comparingInt(f -> f.getWeight()).thenComparing(e -> e.getU() + e.getV() + e.getWeight()));