Java8 lambda表达式,Comparator.comparing().thenComparing()报错

2022-07-21 13:45:16

环境

Java:1.8+

前言

今天发了一个问题:
在这里插入图片描述

问题描述:

  1. List进行排序,如果在Comparator.comparing()方法中,只使用一个字段排序,没有问题。
  2. 但是如果使用多字段排序,并且写法是lambda时,就会有问题。
  3. 如果使用方法引用可以看到不会报错。

解决

为什么, 下面这种写法会有问题呢?

dcList.sort(Comparator.comparing((p)-> p.getRow()).thenComparing(n-> n.getCol()));
dcList.sort(Comparator.comparing((p)-> p.getRow()).thenComparing(DmnCell::getCol));

也就是说lambda表达式的写法有问题。可是Comparator.comparing()方法,本质上就是传lambda表达式啊。
把鼠标放到报错处,会提示:

Cannot resolve method'getRow' in'Object'

也就是说,p的类型为Object。这说明,p的引用类型没有自动推断出来。要解决这个问题,很简单,手动指定下就可以啦
在这里插入图片描述
可以看到,手动指定类型后,后面的报错也一并解决了。

探究原因

//正常
dcList.sort(Comparator.comparing((p)-> p.getRow()));//不正常;这种写法会报错
dcList.sort(Comparator.comparing((p)-> p.getRow()).thenComparing(n-> n.getCol()));

为什么这种lambda表达式,推断不出类型呢?

首先,我们知道如果没有thenComparing()方法,那么编译器,根据上下文,其实这里也就只有上文dcList可知,p的类型应该是DmnCell
但是,后面有了thenComparing()方法之后,编译器根据上文信息可知可能是DmnCell类型,但是却不知下文(thenComparing())实际会返回什么类型;(下文输入类型可能知道可能不知道);所以这里,在comparing方法这里,返回的目标类型推断失败,失败的类型默认就是Object

也就是我们可以得出,lambda表达式类型推断,需要明确上文信息和下文的信息。具体点,上文会传什么类型过来,下文会返回什么类型。只有上下文都明确的地方,目标类型才会推断出来。(以上是个人猜想,并没有什么权威断言)。

再举个例子

//没问题,可以推断出来publicstaticComparator<CustUser>createUser1(){return(CustUser user1,CustUser user2)-> user1.getAge()- user2.getAge();}//没问题,可以推断出来publicstaticComparator<CustUser>createUser2(){return(user1, user2)-> user1.getAge()- user2.getAge();}

如果我们将上面的return语句拆分成两条,会出现问题问题呢?

//有问题,不可以推断出来Comparator comparator=(user1, user2)-> user1.getAge()- user2.getAge();

这时候就会编译报错,说找不到getAge方法。这是因为我们返回的Comparator并没有指明类型,所以默认情况下是Object类型。Object类型并没有getAge方法,所以报错。

我们可以这样改写:

//没问题,可以推断出来Comparator<CustUser> comparator=(user1, user2)-> user1.getAge()- user2.getAge();

总结

当写lambda时,如果遇到原本可以正常写,但是又突然不能写或写了就报错的情况,很可能就是没有明确目标类型,此时,只需要明确指定目标类型即可。

目标类型:Lambda表达式的类型,也称为 目标类型。

参考地址

JAVA8 LAMBDA表达式,COMPARATOR.COMPARING().THENCOMPARING()报错

Java中的类型推断和lambda表达式

  • 作者:山鬼谣me
  • 原文链接:https://blog.csdn.net/u013066244/article/details/122884996
    更新时间:2022-07-21 13:45:16