2017-11-03 91 views
12

Próbuję zrozumieć, jak działa funkcja Comparator.comparing. Stworzyłem własną metodę porównywania, aby ją zrozumieć.Java Lambda do konwersji komparatora - reprezentacja pośrednia

private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) { 
    BiFunction<T,T,Integer> bfun = (T a, T b) -> f.apply(a).compareTo(f.apply(b)); 
    return (Comparator<T>) bfun; 
} 

Ostatni wiersz w tej funkcji zgłasza wyjątek.

Jeśli jednak zmienić tę funkcję do

private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) { 
    return (T a, T b) -> f.apply(a).compareTo(f.apply(b)); 
} 

To działa tak samo dobrze, jak oczekiwano.

Jaki jest pośredni interfejs funkcjonalny, którego używa druga próba, który jest w stanie przekonwertować lambda na Comparator?

+4

Typ, do którego konwertuje lambda, to typ, z którego wyrażenie musi pochodzić z kontekstu. W pierwszym przykładzie lambda musi przekształcić się w 'BiFunction', ponieważ jest to typ zmiennej, do której jest przypisany. W drugim przykładzie lambda musi konwertować na "Komparator", ponieważ jest to typ zwracany przez metodę. 'BiFunction' i' Comparator' mają ten sam "kształt", więc ta sama lambda może stać się zależna od kontekstu, ale są to różne typy, więc rzucanie jeden do drugiego zawiedzie. –

+0

I'm downvoting this. Nie dla jakości, ale dlatego, że w tym pytaniu przeprowadzono szereg audytów, z których * trzy * nie powiodło się. –

Odpowiedz

11

Co to jest pośredni interfejs funkcjonalny, z którego korzysta druga próba, która jest w stanie przekonwertować lambda na Komparator?

Samo to jest Comparator.

W ramach drugiej metody zdefiniowano obiekt Comparator, a nie obiekt pośredni, który został odlany do obiektu Comparator.

Ostatni wiersz w tej funkcji zgłasza wyjątek.

Tak, powinno.

Jeśli dwie klasy są interfejsami funkcjonalnymi i mają podobne metody (z identycznymi sygnaturami i tym samym typem zwrotnym), nie oznacza to, że mogą być używane zamiennie.


Ciekawa sztuczka - można dokonać Comparator<T> odnosząc się do sposobu, BiFunction<T, T, Integer> bfun „s apply:

private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) { 
    final BiFunction<T,T,Integer> bfun = (T a, T b) -> f.apply(a).compareTo(f.apply(b)); 
    return bfun::apply; // (a, b) -> bfun.apply(a, b); 
} 
5

pośredni interfejs funkcjonalny w drugiej próbie po prostu Comparator<T>:

Ty Widzisz to, ponieważ Twój fragment kodu jest równoważny z następującym:

private static <T,U extends Comparable<U>> Comparator<T> comparing(Function<T,U> f) { 
    Comparator<T> comparator = (T a, T b) -> f.apply(a).compareTo(f.apply(b)); 
    return comparator; 
}