2017-09-02 58 views
2

排序的数组列表下面的代码工作:与比较器的Java Lambda表达式

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

回答

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())); 
    } 
} 
+0

据我所知,这并不算作回答的问题*为什么*就是这样。 – Eugene

0

在这样的作品,编译器知道Edge::getWeight预计边缘,因此推断该ToIntFunction<? super T>ToIntFunction<Edge>解决方案。

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

一个快速的解决方案是让编译器知道它的边缘:

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

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

你的第一行代码 -

Comparator.comparingInt(Edge::getWeight) 

实现功能接口ToIntFunction超过T而你的情况是Edge待比较元素的类型,并返回其进一步使用

一个 Comparator<Edge>

在您的第二行代码中 -

Comparator.comparingInt(f -> f.getWeight()) 

f的类型未定义,因此编译将在此处失败。相反,你可以投的f类型边缘,这会简单地以类似的方式工作:

(Comparator.comparingInt((Edge f) -> f.getWeight())) 

虽然现在的编译器可以真正开始暗示有这一样的方法引用来代替这种(1)。

:为什么推理f存在Edge推断类型的线程解释Generic type inference not working with method chaining?