Java8中对Lambda表达式中方法参数的类型推断(一)

最近在学习jdk8新API,jdk8在比较器Comparator接口里新添了大量的default方法和static方法供我们使用,我们可以直接使用这些默认已经实现好的比较器配合使用Lambda表达式来进行比较排序。但Comparator接口是个泛型类,其中的接口都跟泛型有关,所以在使用的时候还是会出现一些跟泛型类型参数有关的问题。
看我的测试用例:

List list = Arrays.asList("nihao", "hello", "world", "welcome");
//按字符串长度排序
Collections.sort(list, (item1, item2) -> item1.length() - item2.length() );
list.forEach(System.out::println);

程序正确运行。再看下面的代码:

Java8中对Lambda表达式中方法参数的类型推断(一)_第1张图片

好,代码编译出错,idea给我们提示,无法解析length()这个方法。意思是,java编译器无法从参数item中获取length()这个方法信息。原因只有一个,形参item不是String类型的。那我们看看此时item被编译器解析成的类型变量是:

Java8中对Lambda表达式中方法参数的类型推断(一)_第2张图片

java编译器此时把item当作Object类型,所以找不到length()方法。他推断出的类型并不是我们想要的类型(就是说此时java编译器无法准确去推断出我们lambda表达式里的参数类型),那么我们可以显式地给参数声明它的类型。
改进代码:

Java8中对Lambda表达式中方法参数的类型推断(一)_第3张图片

这样就可以编译通过了。但是我在想为什么java编译器把item当作Object类型呢?其实java编译器推断目标类型跟泛型有关( Java 8 新特性:泛型目标类型推断),来我们看看这个方法的泛型参数:

Java8中对Lambda表达式中方法参数的类型推断(一)_第4张图片

泛型 < ? super T > 的意思是接受的类型参数是T或者T的父类,对List进行排序,编译器可以推断出T为String类型,那么comparingInt(ToIntFunction < ? super T > keyExtractor)在上面的代码中就是接受类型参数为String类型,或者String的更上一级类型。所以java编译器不确定你到底是传什么类型的参数,那么它只能直接推断成最顶级的类型,即Object类型。以保证向下兼容。所以为了更准确的使用lambda参数,我们这里要显式写明参数类型String item。其实我们可以验证一下,刚才说了,这里只接受String或String的更高一级类型。看代码:

这里写图片描述

在这里我显式地定义成Boolean类型的参数item,idea编译报错。因为Stirng的上限为Object没有Boolean类型。好再改一下代码:

这里写图片描述

没有报错。那么按照之前的推断,Serializable应该是String之上的类型。

这里写图片描述

String实现了这些接口,符合泛型 < ? super T > 的定义。

这就是我对这个编译器类型推断的问题分析的整个思考过程。本来自圆其说,以为问题解决了。后来,我看到demo中的第一行代码:

Collections.sort(list, (item1, item2) -> item1.length() - item2.length() );

这里java编译器可以推断出lambda表达式里的参数类型,但是你一看API

Java8中对Lambda表达式中方法参数的类型推断(一)_第5张图片

我蒙蔽了。。。怎么回事,想了半天,这里怎么解释?还是泛型< ? super T >为什么这里他可以推断出item1,item2是String类型呢?

你可能感兴趣的:(Java8实战)