当前位置: 首页 > 面试题库 >

Java 8比较器比较静态功能

林铭
2023-03-14
问题内容

对于Comparator类中的比较源代码

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

我明白之间的差别superextends。我不明白的是,为什么这种方法有他们。有人可以给我一个关于参数看起来像这样无法实现的示例Function<T, U> keyExtractor吗?

例如 :

Comparator<Employee> employeeNameComparator = Comparator.comparing(Employee::getName);

也可以使用以下函数定义进行编译

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

问题答案:

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

对问题的非正式讨论

首先,逆变? super T

假设您有两个类,Car并且PhysicalObject这样一个Car extends PhysicalObject。现在假设您有一个Weight可扩展的功能Function<PhysicalObject, Double>

如果声明为Function<T,U>,则您将无法重用该函数Weight extends Function<PhysicalObject, Double>来比较两辆车,因为Function<PhysicalObject, Double>将不符合Function<Car, Double>。但是您显然 希望 能够通过重量比较汽车。因此,逆变量? super T是有意义的,因此Function<PhysicalObject, Double>符合Function<? super Car, Double>

现在是协变? extends U声明。

假设您有两个类,Real并且PositiveReal这样PositiveReal extends Real,并且进一步假设RealComparable

假设Weight前面示例中的函数实际上具有稍微更精确的类型Weight extends Function<PhysicalObject, PositiveReal>。如果申报keyExtractorFunction<? super T, U>的而不是Function<? super T, ? extends U>,您将无法充分利用的事实,PositiveReal也是一个Real,因此有两个PositiveReals不能互相比较,虽然它们实现Comparable<Real>,没有不必要的限制Comparable<PositiveReal>

总结:与声明Function<? super T, ? extends U>,则Weight extends Function<PhysicalObject, PositiveReal>可以替换为一个Function<? super Car, ? extends Real>比较Car使用S Comparable<Real>

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

代码:如果省略? extends或,? super则完全列举后果

这是一个可以汇编的例子,其中系统地列举了如果省略? super或可能出错的所有事物? extends。此外,显示了两个(难看的)部分解决方法。

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中定义站点协方差和协方差的详细说明:如何检查函数中元素的协方差和协方差位置?


 类似资料:
  • 假设我有一个双人课 我希望对它进行排序,首先是第一个值,然后是第二个值。现在,如果我这样做 一切都很好,列表按对的第一个值排序,但如果我这样做 它因错误而失败 好吧,所以它可能无法推断参数,所以如果我这样做 它因错误而失败 为什么它适用于comparing()而不适用于comparing()。然后比较()?

  • 我想用Lambda对列表排序: 但我得到了这个编译错误:

  • 我想知道是否可以制作实现比较器接口的非静态内部类。 例如:。 我想使用比较器类非静态,因为我想使用非静态字段“num”并想修改它的值。有非静态比较器内部类可以吗? 附加信息 对于每个对象,我都在计算内部的分数,并进行相应的比较和排序。我需要将这些分数保存在我在comparator内计算的地图中,并希望在外部类中使用该地图进行进一步计算。

  • 我有一个关于compareTo函数如何帮助比较器排序的问题,即o1。比较(o2)与o2。比较(o1) 如果两个字符串相等,则此方法返回0,否则返回正值或负值。如果第一个字符串在词典上大于第二个字符串,则结果为正,否则结果为负。 上面的陈述很简单,但是为什么o1.compare(o2)会给我一个升序,而o2.compare(o1)给了我一个降序? 如果我有整数值“5,10,3”,我得到3,5,10和

  • 我有一个ArrayList,需要按降序排序。我用java来实现它。util。流动流动排序(比较器)方法。以下是根据Java API的描述: 返回由该流的元素组成的流,根据提供的