2017-09-02 63 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?