Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparator comparing type inference

Tags:

java

Let's say change Comparator.comparing source code from

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));
}

to

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));
}

And we have the follwing classes

class PhysicalObject {
  double weight;
  public Double getWeight(){
    return weight;  
  }
}
class Car extends PhysicalObject {}

The following statament does not compile

Function<PhysicalObject, Double> weight = p->p.getWeight();

Comparator<Car> c = HypotheticComparators.comparing(weight);

while this compile Comparator<Car> c3_1 = HypotheticComparators.comparing(PhysicalObject::getWeight);

I understand that the first statement can't compile is because the modified comparing function does not have the bounded wildcard (? super T), but why the second statement can compile without any problem ?

like image 883
Jiaming Li Avatar asked Apr 22 '26 01:04

Jiaming Li


1 Answers

With comparing defined as:

Comparator<T> comparing(Function<T, U> keyExtractor) // abbreviated

the statement:

Comparator<Car> c = comparing(weight);

requires argument to be a Function<Car, ?>, but weight is a Function<PhysicalObject, Double> so you get the compile error.

However, when doing

Comparator<Car> c3_1 = comparing(PhysicalObject::getWeight);

the Function<Car, ?> method ? apply(Car t) is adequately implemented by the Double getWeight() of superclass PhysicalObject, since t->getWeight() is a call to that method.

The PhysicalObject::getWeight method reference is like the following lambda:

Comparator<Car> c3_1 = comparing((Car t) -> {
    PhysicalObject p = t;
    return p.getWeight(); // call PhysicalObject::getWeight
});

Or the following anonymous class:

Comparator<Car> c3_1 = comparing(new Function<Car, Double>() {
    @Override
    public Double apply(Car t) {
        PhysicalObject p = t;
        return p.getWeight();
    }
});

The widening conversion from Car to PhysicalObject is allowed in a method reference.

like image 59
Andreas Avatar answered Apr 23 '26 14:04

Andreas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!