2015-08-25 13 views
5

Lettura del Java Tutorial by Oracle on interfaces che fornisce un esempio su Card (Carte da gioco) Stavo cercando di capire lo default methods in interfaces. Ecco la link, sezione "Integrazione dei metodi predefiniti nelle interfacce esistenti". Ora nell'ultima sezione hanno ordinato le carte prima per livello e poi per seme. Sono state fornite le seguenti logiche. Si supponga che qualunque interfacce, funzioni o classi che vengono utilizzati sono stati definiti e sort funzione richiede una logica ComparatorCatena di comparatori in java

1:

package defaultmethods; 

import java.util.*; 
import java.util.stream.*; 
import java.lang.*; 

public class SortByRankThenSuit implements Comparator<Card> { 
    public int compare(Card firstCard, Card secondCard) { 
     int compVal = 
      firstCard.getRank().value() - secondCard.getRank().value(); 
     if (compVal != 0) 
      return compVal; 
     else 
      return firstCard.getSuit().value() - secondCard.getSuit().value(); 
    } 
} 

Logic 2:

myDeck.sort(
    Comparator 
     .comparing(Card::getRank) 
     .thenComparing(Comparator.comparing(Card::getSuit))); 

Ora sto avendo alcuni problemi nella comprensione della seconda logica. Ho letto le interfacce di confronto e i nuovi metodi statici che sono stati inclusi in Java 1.8. Ora capisco qualcosa di simile a questo myDeck.sort(Comparator.comparing(Card::getRank)) che ordina per grado ma dopo aver letto the documentation for thenComparing, non riesco a capire come thenComparing restituisce un Comparator che raggiunge la logica precedente 1. Costruisce internamente qualcosa come il costrutto if-else come specificato in Logica 1?

risposta

6

Sì, crea internamente qualcosa di simile, solo con più lambda intermedi. Supponendo che i vostri getRank e getSuit metodi restituiscono alcune istanze di classi comparabili Rank e Suit, nel tuo caso si ha modo efficace:

Function<Card, Rank> toRank = Card::getRank; 
Comparator<Card> comp1 = (a, b) -> toRank.apply(a).compareTo(toRank.apply(b)); 
Function<Card, Suit> toSuit = Card::getSuit; 
Comparator<Card> comp2 = (a, b) -> toSuit.apply(a).compareTo(toSuit.apply(b)); 
Comparator<Card> result = (a, b) -> { 
    int res = comp1.compare(a, b); 
    return res != 0 ? res : comp2.compare(a, b); 
}; 

Così, dopo inlining (che potrebbe essere eseguita da JIT-compilatore) si può avere qualcosa di simile :

Comparator<Card> result = (a, b) -> { 
    int res = a.getRank().compareTo(b.getRank()); 
    return res != 0 ? res : a.getSuit().compareTo(b.getSuit()); 
}; 

si noti che è possibile utilizzare la versione più semplice:

myDeck.sort(
    Comparator 
     .comparing(Card::getRank) 
     .thenComparing(Card::getSuit)); 
10

Questa è l'implementazione sulla mia macchina (Oracle JDK 8u40)

default Comparator<T> thenComparing(Comparator<? super T> other) { 
    Objects.requireNonNull(other); 
    return (Comparator<T> & Serializable) (c1, c2) -> { 
     int res = compare(c1, c2); 
     return (res != 0) ? res : other.compare(c1, c2); 
    }; 
} 

quindi sì, è essenzialmente se il resto (più precisamente, l'operatore ternario).

+0

Wh Prima possiamo controllare il codice sorgente di Oracle JDK? – AbKDs

+1

Il mio IDE (IntelliJ) lo preme per me. Sul mio Mac è in: /Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home/src.zip!/java/util/Comparator.java – RedDeckWins

+3

@AbKDs, nel file src.zip all'interno dell'installazione di JDK . Oppure [online] (http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/8u40-b25/java/util/Comparator.java#Comparator.thenComparing%28java.util.Comparator % 29). –