Java 8比较器比较静态功能 [英] Java 8 Comparator comparing static function

查看:127
本文介绍了Java 8比较器比较静态功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于Comparator类中的比较源代码

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

我了解 super 扩展。我不明白的是,为什么这种方法有他们。有人可以给我一个例子,说明参数看起来像 Function< T,U& keyExtractor

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 ?

例如:

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


推荐答案

下面是一个简单的示例:按重量比较汽车。我将首先以文本形式描述该问题,然后演示各种可能的方法,如果怎么会出错?扩展? super 被省略。我还将展示在每种情况下都可用的丑陋的部分解决方法。 如果您喜欢代码而不是散文,请直接跳至第二部分,这应该是不言自明的。

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.

首先,对变量?超级T

假设您有两个类,分别是 Car PhysicalObject ,这样 Car扩展了PhysicalObject 。现在假设您有一个扩展 Weight 的函数 Function< PhysicalObject,Double>

Suppose that you have two classes Car and PhysicalObject such that Car extends PhysicalObject. Now suppose that you have a function Weight that extends Function<PhysicalObject, Double>.

如果声明是 Function< T,U> ,那么您将无法重用函数 Weight扩展Function< PhysicalObject,Double> 来比较两辆车,因为 Function< PhysicalObject,Double> 不符合 Function< Car, Double> 。但是您显然想要能够根据汽车的重量进行比较。因此,反变量?超级T 是有意义的,因此 Function< PhysicalObject,Double> 符合 Function< ;?超级汽车,Double>

If the declaration were Function<T,U>, then you couldn't reuse the function Weight extends Function<PhysicalObject, Double> to compare two cars, because Function<PhysicalObject, Double> would not conform to Function<Car, Double>. But you obviously want to be able to compare cars by their weight. Therefore, the contravariant ? super T makes sense, so that Function<PhysicalObject, Double> conforms to Function<? super Car, Double>.

现在协变量了吗?扩展了U 声明。

假设您有两个类,分别是 Real PositiveReal ,这样 PositiveReal扩展了Real ,并进一步假定 Real 可比较

Suppose that you have two classes Real and PositiveReal such that PositiveReal extends Real, and furthermore assume that Real is Comparable.

假设您的函数 Weight 示例实际上具有稍微更精确的类型 Weight扩展了Function< PhysicalObject,PositiveReal> 。如果 keyExtractor 的声明是 Function< ;?超级T,U> 而不是 Function< ;?超级T ,?扩展U> ,您将无法利用 PositiveReal 也是 Real 的事实code>,因此两个 PositiveReal 不能相互比较,即使它们实现了 Comparable< Real> ,而没有不必要的限制 Comparable< PositiveReal>

Suppose that your function Weight from the previous example actually has a slightly more precise type Weight extends Function<PhysicalObject, PositiveReal>. If the declaration of keyExtractor were Function<? super T, U> instead of Function<? super T, ? extends U>, you wouldn't be able to make use of the fact that PositiveReal is also a Real, and therefore two PositiveReals couldn't be compared with each other, even though they implement Comparable<Real>, without the unnecessary restriction Comparable<PositiveReal>.

总结:带有声明 Function< ;?超级T ,?扩展U> Weight扩展Function< PhysicalObject,PositiveReal> 可以代替 Function< ;?超级跑车?扩展Real> 以使用 Comparable< Real> 比较 Car

To summarize: with the declaration Function<? super T, ? extends U>, the Weight extends Function<PhysicalObject, PositiveReal> can be substituted for a Function<? super Car, ? extends Real> to compare Cars using the Comparable<Real>.

我希望这个简单的例子可以阐明为什么这样的声明有用。

I hope this simple example clarifies why such a declaration is useful.

这里是一个可编译的示例,其中系统地枚举了所有可能会出错的事物,如果我们省略?超级?扩展。此外,还显示了两个(难看的)部分解决方法。

Here 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.

import java.util.function.Function;
import java.util.Comparator;

class HypotheticComparators {

  public static <A, B> Comparator<A> badCompare1(Function<A, B> f, Comparator<B> cb) {
    return (A a1, A a2) -> cb.compare(f.apply(a1), f.apply(a2));
  }

  public static <A, B> Comparator<A> badCompare2(Function<? super A, B> f, Comparator<B> cb) {
    return (A a1, A a2) -> cb.compare(f.apply(a1), f.apply(a2));
  }

  public static <A, B> Comparator<A> badCompare3(Function<A, ? extends B> f, Comparator<B> cb) {
    return (A a1, A a2) -> cb.compare(f.apply(a1), f.apply(a2));
  }

  public static <A, B> Comparator<A> goodCompare(Function<? super A, ? extends B> f, Comparator<B> cb) {
    return (A a1, A a2) -> cb.compare(f.apply(a1), f.apply(a2));
  }

  public static void main(String[] args) {

    class PhysicalObject { double weight; }
    class Car extends PhysicalObject {}
    class Real { 
      private final double value; 
      Real(double r) {
        this.value = r;
      }
      double getValue() {
        return value;
      }
    }
    class PositiveReal extends Real {
      PositiveReal(double r) {
        super(r);
        assert(r > 0.0);
      }
    }

    Comparator<Real> realComparator = (Real r1, Real r2) -> {
      double v1 = r1.getValue();
      double v2 = r2.getValue();
      return v1 < v2 ? 1 : v1 > v2 ? -1 : 0;
    };
    Function<PhysicalObject, PositiveReal> weight = p -> new PositiveReal(p.weight);

    // bad "weight"-function that cannot guarantee that the outputs 
    // are positive
    Function<PhysicalObject, Real> surrealWeight = p -> new Real(p.weight);

    // bad weight function that works only on cars
    // Note: the implementation contains nothing car-specific,
    // it would be the same for every other physical object!
    // That means: code duplication!
    Function<Car, PositiveReal> carWeight = p -> new PositiveReal(p.weight); 

    // Example 1
    // badCompare1(weight, realComparator); // doesn't compile
    // 
    // type error:
    // required: Function<A,B>,Comparator<B>
    // found: Function<PhysicalObject,PositiveReal>,Comparator<Real>

    // Example 2.1
    // Comparator<Car> c2 = badCompare2(weight, realComparator); // doesn't compile
    // 
    // type error:    
    // required: Function<? super A,B>,Comparator<B>
    // found: Function<PhysicalObject,PositiveReal>,Comparator<Real>

    // Example 2.2
    // This compiles, but for this to work, we had to loosen the output
    // type of `weight` to a non-necessarily-positive real number
    Comparator<Car> c2_2 = badCompare2(surrealWeight, realComparator);

    // Example 3.1
    // This doesn't compile, because `Car` is not *exactly* a `PhysicalObject`:
    // Comparator<Car> c3_1 = badCompare3(weight, realComparator); 
    // 
    // incompatible types: inferred type does not conform to equality constraint(s)
    // inferred: Car
    // equality constraints(s): Car,PhysicalObject

    // Example 3.2
    // This works, but with a bad code-duplicated `carWeight` instead of `weight`
    Comparator<Car> c3_2 = badCompare3(carWeight, realComparator);

    // Example 4
    // That's how it's supposed to work: compare cars by their weights. Done!
    Comparator<Car> goodComparator = goodCompare(weight, realComparator);

  }
}






相关链接


  1. Scala中定义站点协方差和协方差的详细图示:如何检查函数中元素的协变和协变位置?

  1. Detailed illustration of definition-site covariance and contravariance in Scala: How to check covariant and contravariant position of an element in the function?

这篇关于Java 8比较器比较静态功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆