For the comparing source code in Comparator class
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<? super T, ? extends U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
I understand the difference between super
and extends
. What i dont understand is that why this method have them. Can someone give me an example on what cannot be achieved when the parameter look like this Function<T, U> keyExtractor
?
For example :
Comparator<Employee> employeeNameComparator = Comparator.comparing(Employee::getName);
can also compile with the following function definition
public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
Function<T, U> keyExtractor)
{
Objects.requireNonNull(keyExtractor);
return (Comparator<T> & Serializable) (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
}
Here is a simple example: comparing cars by weight. I will first describe the problem in text-form, and then demonstrate every possible way how it can go wrong if either
? extends
or? super
is omitted. I also show the ugly partial workarounds that are available in every case. If you prefer code over prose, skip directly to the second part, it should be self-explanatory.Informal discussion of the problem
First, the contravariant
? super T
.Suppose that you have two classes
Car
andPhysicalObject
such thatCar extends PhysicalObject
. Now suppose that you have a functionWeight
that extendsFunction<PhysicalObject, Double>
.If the declaration were
Function<T,U>
, then you couldn't reuse the functionWeight extends Function<PhysicalObject, Double>
to compare two cars, becauseFunction<PhysicalObject, Double>
would not conform toFunction<Car, Double>
. But you obviously want to be able to compare cars by their weight. Therefore, the contravariant? super T
makes sense, so thatFunction<PhysicalObject, Double>
conforms toFunction<? super Car, Double>
.Now the covariant
? extends U
declaration.Suppose that you have two classes
Real
andPositiveReal
such thatPositiveReal extends Real
, and furthermore assume thatReal
isComparable
.Suppose that your function
Weight
from the previous example actually has a slightly more precise typeWeight extends Function<PhysicalObject, PositiveReal>
. If the declaration ofkeyExtractor
wereFunction<? super T, U>
instead ofFunction<? super T, ? extends U>
, you wouldn't be able to make use of the fact thatPositiveReal
is also aReal
, and therefore twoPositiveReal
s couldn't be compared with each other, even though they implementComparable<Real>
, without the unnecessary restrictionComparable<PositiveReal>
.To summarize: with the declaration
Function<? super T, ? extends U>
, theWeight extends Function<PhysicalObject, PositiveReal>
can be substituted for aFunction<? super Car, ? extends Real>
to compareCar
s using theComparable<Real>
.I hope this simple example clarifies why such a declaration is useful.
Code: Full enumeration of the consequences when either
? extends
or? super
is omittedHere is a compilable example with a systematic enumeration of all things that can possibly go wrong if we omit either
? super
or? extends
. Also, two (ugly) partial work-arounds are shown.Related links
Let's say, for example, we want to compare commercial flights by what plane they use. We would therefore need a method that takes in a flight, and returns a plane:
That is, of course, a
Function<CommercialFlight, Plane>
.Now, the important thing is that the function returns a
Plane
. It doesn't matter what kind of plane is returned. So a method like this should also work:Now technically this is a
Function<CommercialFlight, CivilianPlane>
, which is not the same as aFunction<CommercialFlight, Plane>. So without the
extends`, this function wouldn't be allowed.Similarly, the other important thing is that is can accept a
CommercialFlight
as an argument. So a method like this should also work:Technically, this is a
Function<Flight, Plane>
, which is also not the same as aFunction<CommercialFlight, Plane>
. So without thesuper
, this function wouldn't be allowed either.