Comparator.reversed()颠倒排序时,使用lambda报错

目的:对list中元素的属性做操作之后进行颠倒排序,使用lambda表达式报错,

提示:Cannot resolve method 'getContributionProportion' in 'Object' 

场景:

首先,获取到list,然后对list中的元素根据某个属性进行某些操作之后排序,使用lambda表达式会报错,如下,会提示Cannot resolve method 'getContributionProportion' in 'Object'。

1、使用lambda表达式,进行排序,会报错

1、List<Employee> list = employeeService.listByIds(idList);
list.sort(Comparator.comparing(o -> new BigDecimal(o.getContributionProportion())).reversed());
2、不使用lambda表达式时,直接使用方法引用,不会报错,但是没有达到需求
2、list.sort(Comparator.comparing(Employee::getContributionProportion).reversed());

3、使用lambda表达式,不进行颠倒排序,也不会报错,但是也没有达到需求

3、list.sort(Comparator.comparing(o -> new BigDecimal(o.getContributionProportion())));

4、正确的写法:

4、list.sort(Comparator.comparing((Employee o) -> new BigDecimal(o.getContributionProportion())).reversed());

        如果不使用方法引用,要传递一些其他的参数,使用lambda表达式时,这个时候,可以在lambda中显示提供参数类型。

        当然,如果不是这样的写法,分开来处理,也是可以多种方式实现业务需求的,现在只是针对这种方式讲一下是为什么会报错。

先简单了解一下lambda表达式:

        Lambda 表达式中的参数类型都是由编译器推断得出的。 Lambda 表达式中无需指定类型,程序依然可以编译,这是因为 javac 根据程序的上下文,在后台推断出了参数的类型。 Lambda 表达式的类型依赖于上下文环境,是由编译器推断出来的。这就是所谓的 “类型推断”。Lambda表达式会有类型检查和类型推断这两个过程,保证了Lambda使用的正确性。

类型检查:主要就是检查Lambda表达式是否能正确匹配函数式接口的方法。

类型推断:当Lambda表达式没有显式声明参数类型,JVM编译器会通过目标类型推断入参类型。

Lambda的上下文:使用Lambda表达式来传递的方法的参数,或接受Lambda表达式的值的局部变量        

目标类型:是指Lambda表达式所在上下文环境的类型。比如,将 Lambda 表达式赋值给一个局部变量,或传递给一个方法作为参数,局部变量或方法参数的类型就是 Lambda 表达式的目标类型。


第一种分析:

        sort()的参数是Comparator<? super E> c,这里在对list进行排序时,此时的E是根据前面list推断出是Employee类型,那参数必须也是这个类型,list.sort()就需要传的参数是Comparator<? super Employee> c,也就是说Comparator.comparing()需要返回的类型为Comparator<Employee>,这意味着Comparator.comparing()需要Function采用一个Employee传入参数。

        2、4指定了类型,也就不需要作类型推断了,肯定能编译通过。

       3去掉了reversed()为什么可以编译通过?因为Comparator.comparing()没有指定具体的泛型参数,在方法调用前面使用<>指定,或给方法传入具体类型的入参,编译器也可以推断出来,否则会默认从sort()入参类型里推断,这里就默认从sort()的入参类型推断为Employee。

        1为什么编译失败?reversed()的返回类型依赖前一个方法的返回类型推断,Comparator.comparing()又依赖它的入参Function<? super T, ? extends U> keyExtractor推断,但是它的入参没有明确的类型,那么它只能直接推断成最顶级的类型,即Object类型。这里为什么没有默认从sort()入参类型里推断呢?注意,这里的比较器是多层的,comparing()和reversed(),最终我们需要的比较器是reversed()返回的,因为编译器的类型推断机制不够强大,无法同时采取两个步骤,推断不出来类型,也就是无法从上下文中推断出类型。个人的理解,lambda表达式要推断类型的时候,如果是一层操作,可以根据上下文推断出来,如果是多层操作则推断不出来,变成多个上下文,而reversed()是后操作的,是离lambda表达式最近的上下文,两层上下文,参数是未知的,就变成object,lambda推断的就是object。

第二种分析:

list.sort(Comparator.comparing(o -> new BigDecimal(o.getContributionProportion())));

list.sort(Comparator.comparing(o -> new BigDecimal(o.getContributionProportion())).reversed());

        再来对比一下这两种写法,o -> new BigDecimal(o.getContributionProportion())看成一个整体。

第一种写法:推断类型的时候,根据目标类型推断,也就是根据Comparator.comparing()的参数类型推断,因为comparing()的参数类型和返回类型是一个类型,这里只有一个comparing()操作,且sort()需要Employee类型,即comparing()需要返回Employee类型,综合,推断o类型是Employee;

第二种写法:整体看,sort()需要Employee类型,也就是原本需要Comparator.comparing(o -> new BigDecimal(o.getContributionProportion())).reversed()返回一个Employee类型,由于这里有两个操作,最终返回Employee类型,所以编译器推断的时候并不确定comparing()的参数传的就是Employee类型,所以推断成它的父类Object,因此就推断了o类型是Object类型,而sort()不需要Object类型,所以报错。

  • 14
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值