How do I interpret the argument of method comparing(Function<? super T,? extends U> keyExtractor)?

Viewed 1348

Full signature of method:

public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)

I'm learning lambda expressions and I have this piece of code that compare a List of employees and order them by the name field:

List<Employee> employees = new ArrayList<>();

Collections.sort(employees, Comparator.comparing(Employee::getName));

The code works fine but I have looked at Comparator functional interface in docs and I have found the signature of the method "comparing()".

comparing(Function<? super T,? extends U> keyExtractor)

I don't get the parameter of comparing(). How do I know that the parameter accepts a lambda exprssion? And how is interpreted the constrains: <? super T,? extends U> keyExtractor?

I know that super means that ? has to be type T or above in the hierarchical inheritance, and ? also must be of type U and below in the hierarchical inheritance. But how can we traduce that in my example?

It can be interpreted like this: ? must be of type Employees and above in inheritance chain and the name field must be type Employees or below in inheritance chain? Or ? must be type Array List and above and ? must be type Employees List and below?

2 Answers

How do I know that the parameter accepts a lambda expersion?

By looking at the interface of the argument it accepts. In this case, the argument type is Function, which is a functional interface (this name does not really have any connection to the name of the interface - you can name your interfaces however you want). A functional interface is an interface that has only one unimplemented function (the additional distinction comes from a fact that interfaces can have default implementations).

Take a look at Function:

@FunctionalInterface
public interface Function<T, R> {
    R apply(T t);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {
        Objects.requireNonNull(before);
        return (V v) -> apply(before.apply(v));
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {
        Objects.requireNonNull(after);
        return (T t) -> after.apply(apply(t));
    }

    static <T> Function<T, T> identity() {
        return t -> t;
    }
}

There is only one unimplemented method - it's called apply. When you create a lambda that's supposed to be a Function, that lambda's body will be used to implement apply.

You may be confused about the @FunctionalInterface - it's not required. It's just an annotation for convenience purposes.


About the <? super T,? extends U>, these are constraints on generic types. It means that said Function needs an argument that's a supertype T and will return something that is derived from U. This is a fairly complicated topic. You can read more about it here.

Full signature of the method:

public static <T, U extends Comparable<? super U>> Comparator comparing( Function<? super T, ? extends U> keyExtractor)

Citing from docs:

Accepts a function that extracts a Comparable sort key from a type T, and returns a Comparator that compares by that sort key.

So, to this point we know that comparing() method accept as parameter a function, and that is a Functional Interface that @Fureeish has explained in the previous answer. And because lambda expressions are build around functional interfaces, we know that we can use it as parameter.

Type Parameters:

T - the type of element to be compared U - the type of the Comparable sort key

T, in regard of the definition above is of type Employee, because we want to compare type of employees or objects that their class are super classes of Employee. ? super T, means that placeholder ? must be type T or above in the chain of inheritance.

U, is type String, it's the "name" field, and String implements Comparable (see docs), as to respect the method definition:

public static <T, U extends Comparable<? super U>> Comparator

The parameter method return a Comparator that compares by an extracted key.

Related