2017-09-02 2 views
2

Le code suivant pour trier une liste de tableau fonctionne:Java Lambda Expression avec Comparator

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

tout en faisant chose même une autre façon provoque une erreur de temps de compilation

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

g.edges() retourne une liste de tableau de bords .

Pourquoi cela se produit-il que la première méthode fonctionne alors que la seconde ne marche pas? edges.sort(Comparator.comparingInt(f -> f.getWeight()) fonctionne bien comme edges.sort(Comparator.comparingInt(Edge::getWeight)) mais la première méthode ne permet pas d'utiliser .thenComparing(\*lambda exp*\) tandis que la seconde permet de l'utiliser. Pourquoi cela est-il ainsi?

Et la classe Edge -

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

Répondre

1

Si vous lisez le message d'erreur que vous obtenez un indice:

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

Il semble donc que le compilateur a une limitation déduisant des arguments de type par les chaînes de méthodes comme ce. Il y a plusieurs façons de donner le compilateur quelques conseils:

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

pour autant que je peux dire cela ne compte pas comme une réponse à la question de * pourquoi * c'est comme ça. – Eugene

0

Dans la solution qui fonctionne, le compilateur sait que Edge::getWeight attend un bord et donc que le infère ToIntFunction<? super T> est un ToIntFunction<Edge>. Cependant, en utilisant un lambda, le compilateur ne peut pas déduire le type (par conséquent, il ne sait pas qu'il s'agit d'un Edge et le traite comme un objet).

Une solution rapide est de laisser le compilateur savoir qu'il est un Edge:

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

C'est la définition de <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor).

Votre première ligne de code -

Comparator.comparingInt(Edge::getWeight) 

implémente l'interface fonctionnelle ToIntFunction sur T qui dans votre cas est Edge le type d'élément à comparer et renvoie une Comparator<Edge> qui est encore utilisé par

Dans votre deuxième ligne de code -

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

le type de f n'est pas défini et par conséquent la compilation échouerait ici. Au lieu de cela, vous pourriez lancer le type de f Edge, ce serait tout simplement travailler d'une manière similaire:

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

mais maintenant le compilateur peut réellement commencer à penser à la remplacer par la référence de la méthode qui est la même que (1).

Remarque: Pourquoi la conclusion à f étant de type Edge est déduit est expliqué dans le fil Generic type inference not working with method chaining?