【问题标题】:Calling a Method on Lambda Expression在 Lambda 表达式上调用方法
【发布时间】:2019-12-15 02:33:52
【问题描述】:

有没有办法在 lambda 表达式上调用方法?

考虑以下在 MileageComparator 上调用 reversed() 方法的示例: Collections.sort(cars, new MileageComparator().reversed());

但是,如果我将 MileageComparator 编写为带有 reversed() 调用的 Lambda 表达式,则在编写时会出错 Collections.sort(cars, ((Car car1, Car car2) -> (int) (car2.getMileage() - car1.getMileage())).reversed()); 虽然它可以正常工作而无需反转。

我确实知道我可以简单地交换 car1 和 car2 以获得相同的结果,但是我想知道通常是否可以对 lambda 表达式进行方法调用。

【问题讨论】:

  • 使用(Car car1, Car car2) -> (int) (car2.getMileage() - car1.getMileage()) 进行比较是一种不好的做法。在Comparator 类中查看compare 方法文档。

标签: java methods lambda expression


【解决方案1】:

不过,我想知道一般情况下是否可以对 lambda 表达式进行方法调用。

不是,因为 lambda 表达式本身什么都不是。

lambda 表达式是用于实现函数式接口的语法糖。如果没有定义方法签名的接口,lambda 表达式不知道它是什么。

这就像使用未定义的类型名称创建一个匿名类,例如

new Foo() {
    public void bar() {
        // This will not work
    }
}

如果Foo 不存在,该匿名类将无法编译。

同样,(Car a) -> a.openDoor() 将无法编译,因为编译器不知道正在实现什么类型。为了使其工作,编译器需要知道要实现哪个功能接口,例如

Consumer<Car> x = (Car a) -> a.openDoor();

但以下将失败并出现错误Lambda expression needs an explicit target-type

var x = (Car a) -> a.openDoor();

当您将 lambda 表达式包装在括号中并对其调用方法时,编译器无法推断出任何功能接口,这就是失败的原因:

((Car a) -> a.openDoor()).accept(myCar)

但是,您可以通过提供强制转换来告诉编译器要实现哪个接口:

((Consumer<Car>) (Car a) -> a.openDoor()).accept(myCar)

【讨论】:

    【解决方案2】:

    您拥有的 lambda 表达式可以与许多类型相关联,例如 ComparatorCar 类型以及 BiFunction,因此编译器不知道如何解释尚未分配给类型的 reversed() 方法

      Comparator<Car> carComp = (Car car1, Car car2) -> (int) (car2.getMileage() - car1.getMileage());
    
      BiFunction<Car, Car, Integer> biFun = (Car car1, Car car2) -> (int) (car2.getMileage() - car1.getMileage());
    

    从 java-8 开始,您可以使用带有方法引用运算符的静态方法 Comparator.comparing,带有更多示例的 here

    Collections.sort(cars, Comparator.comparing(Car::getMileage).reversed());
    

    因此,通过使用Method References 运算符,您可以创建基于mileage 排序的Comparator 对象

    Comparator<Car> carComp = Comparator.comparing(Car::getMileage);
    

    然后通过调用reversed方法来反转它

    carComp.reversed();
    

    你也可以sort方法从java-8的列表中获得

    cars.sort(Comparator.comparing(Car::getMileage).reversed());
    

    【讨论】:

    • 谢谢。那么一个方法只能在另一个封装了 lambda 表达式而不是表达式本身的方法上调用?
    【解决方案3】:

    几点。

    你试过了,没用。

           Collections.sort(cars, ((Car car1, Car car2) -> (int) (car2.getMileage() - 
                    car1.getMileage())).reversed())
    

    Comparator 和下面的一样:

           Comparator<Car> comp = ((car1, car2)->car1.getMileage() - car2.getMileage()).reversed();
    

    这也不会编译,因为右边的 lambda 对 Comparatorreversed() 方法一无所知。

    但你可以这样做:

            Comparator<Car> comp = (car1, car2)->car1.getMileage() - car2.getMileage();
    

    然后

           Collections.sort(cars, comp.reversed());
    

    因为comp 是一个比较器并且知道reversed() 方法。

    最后一点。使用(a,b)-&gt; a - b 不是一个好主意,因为减去值不会总是产生预期的结果。最好是(a,b)-&gt; (a &gt; b) ? 1 : (a &lt; b) ? -1 : 0

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      • 2011-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多