2014-11-29 13 views
12
public class Test { 
    public static void main(String[] args) { 
     List<Pair<String, Integer>> list = new ArrayList<>(); 
     list.add(new Pair<>("1", 8)); 
     list.add(new Pair<>("3", 2)); 
     list.add(new Pair<>("2", 15)); 

     list.stream() 
      .sorted(Comparator.comparingInt(p -> p.v)) 
      .map(p -> p.k) 
      .forEach(System.out::println); 

    } 
} 

class Pair<K, V> { 
    K k; 
    V v; 
    public Pair(K k, V v) { 
     this.k = k; 
     this.v = v; 
    } 
} 

Ok, come avete capito questo codice sta stampando le mie chiavi coppia dal valore più basso associato al più alto in modo da ottenere i risultati attesi:malinteso circa comparatore in Java 8

Fin qui tutto bene. Ora volevo fare il contrario, ho pensato che avrei dovuto solo fare

list.stream() 
    .sorted(Comparator.comparingInt(p -> p.v).reversed()) 
    .map(p -> p.k) 
    .forEach(System.out::println); 

Ma ottengo un errore di compilazione:

v cannot be resolved or is not a field 

Così sembra comparingInt restituisce un Comparator<Object>. Perché è così? Non dovrebbe restituire un Comparator<Integer>?

Questi sono entrambi riproducibili con Eclipse Luna versione 1 e javac.

javac -version => 1.8.0 
java -version => java version "1.8.0_25" 

Oh anche sentirsi liberi di cambiare il titolo della mia domanda è lo trovate troppo generale, ma non riuscivo a trovare i termini corretti

+0

Probabilmente funzionerà con Comparator.reverseOrder. – assylias

+0

@assy lias Beh, come potrei ottenerlo con reverseOrder? Significherebbe che i miei oggetti coppia sono già comparabili. – user2336315

+0

Ho risposto qui: http://stackoverflow.com/questions/25172595/comparator-reversed-not-compiles-using-lambda –

risposta

8

Credo che sia proprio questo tipo di inferenza sta fallendo, in fondo - perché la chiamata reverse() intralcia il tipo di argomento previsto di sorted() e l'espressione lambda.

Si può fare se si specifica il tipo di comparingInt esplicitamente:

list.stream() 
    .sorted(Comparator.<Pair<String, Integer>>comparingInt(p -> p.v).reversed()) 
    .map(p -> p.k) 
    .forEach(System.out::println); 

O se semplicemente dichiara l'operatore di confronto prima:

Comparator<Pair<String, Integer>> forward = Comparator.comparingInt(p -> p.v); 
list.stream() 
    .sorted(forward.reversed()) 
    .map(p -> p.k) 
    .forEach(System.out::println); 

ci si sente a me come ci dovrebbe essere un Stream.reverseSorted quindi rendi questo tipo di cosa davvero facile, ma non sembra che esista :(

+0

... che è piuttosto brutto, quindi preferisco usare 'ordinato ((p1, p2) -> p2.v.compareTo (p1.v))'. Quindi è probabile che ci sia un bug nel compilatore? – user2336315

+4

@ user2336315: Sono d'accordo che sia brutto, ma questo non significa che sia un bug nel compilatore. Credo che sia una limitazione dell'inferenza di tipo nella lingua, che non è la stessa cosa. Ad essere onesti, non ho mai compreso appieno come funziona l'inferenza di tipo generico in Java (e credo che sia cambiata in alcuni punti nel tempo), ma questo mi sembra decisamente un limite. –

+0

Ah capisco. Forse in una versione futura, questo sarà migliorato. So che hanno già fatto alcune improvvisazioni, ecco perché ho scoperto che era strano che non fosse compilato ... :( – user2336315