5

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?

Bogdan
  • 623
  • 5
  • 13
  • 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? – Bogdan Dec 27 '20 at 18:09
  • 2
    `?` is not the same as a generic type such as `T` and it doesn't mean that both your types of Function has to be in the hierarchy of `Employee`. They are anything of two different types `T` and `U` in simple words, where the `T` would be related to `Employee` based on the types of method type inference since it's been called upon a `List`. – Naman Dec 28 '20 at 04:21
  • 1
    ? is a wildcard of type T and U, and T and U are some type of objects that need to be constraint like in the method signature, no? But I want to know how to interpret this signature so I will know how and why to use it, not to learn by hart. – Bogdan Dec 28 '20 at 08:59

2 Answers2

5

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.

Fureeish
  • 12,533
  • 4
  • 32
  • 62
  • 1
    You mean that "Function" from the argument tell us that is receiving a functional intreface? And how about the restrictions : super T,? extends U> keyExtractor? – Bogdan Dec 27 '20 at 17:45
  • 1
    Yes, but keep in mind that `Function` is a functional interface not because it's named Function, but because an `interface` that's called `Function` has only one method that is not `default`ed. It's called `apply()` and lambda is used to implement that method in an inlined way. – Fureeish Dec 27 '20 at 17:47
  • 1
    Ok, if I have the word Function it denotes a functional interface, whatever functional interface it is. – Bogdan Dec 27 '20 at 17:51
  • Yes I know what is a functional interface, and I know that the annotation is put for clearing purpose, but like a beginner I want to learn how to read the argument. – Bogdan Dec 27 '20 at 17:56
  • 1
    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? – Bogdan Dec 27 '20 at 18:05
  • 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? – Bogdan Dec 27 '20 at 18:09
  • What "*name field*"? – Fureeish Dec 27 '20 at 22:32
  • every employee from the List employees has a field "name" and a getter in respect of this. – Bogdan Dec 27 '20 at 23:11
  • You don't have to return anything `Employee` related in `Comparator`s. You just need an extractor and something comparable (in this specific case). I am not sure I completely understand your follow up questions. I think it may be better for you to digest the question and answers I linked and then ask another question. – Fureeish Dec 27 '20 at 23:26
0

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.

Bogdan
  • 623
  • 5
  • 13