通过上一篇JDK8学习笔记(一)初识lambda表达式 我们jdk8中的lambda表达式有一一个初步认识,这一篇文章是对lambda表达式的一些细节再做些学习。现在我们可以知道,lambda表达式是替换函数式接口出现的地方,是把一个行为参数化了,或者说方法的某个参数(这个参数是函数式接口)传递了一个行为,是一种更加简洁易懂的写法。
本篇文章再介绍一些其他关于lambda表达式的其他概念和细节,比如函数描述符,方法引用、lambda表达式是如何类型检查的?lambda表达式类型推断,复合lambda表达式的写法。
1、函数描述符
函数式接口的抽象方法的签名基本上就是Lambda表达式的签名。我们将这种抽象方法叫作函数描述符。例如,Runnable接口可以看作一个什么也不接受什么也不返回(void)的函数的签名,因为它只有一个叫作run的抽象方法,这个方法什么也不接受,什么也不返回(void)。
函数描述符也叫lambda表达式签名
这个Runnable接口的函数描述符就是:()-> void 。还有其他的函数式接口的描述符如下:
Predicate<T> T->boolean
Consumer<T> T->void
Function<T,R> T->R
2、lambda表达式的类型检查、类型推断
类型检查过程可以分解为如下所示:
首先,你要找出filter方法的声明。
第二,要求它是Predicate<Apple>(目标类型)对象的第二个正式参数。
第三,Predicate<Apple>是一个函数式接口,定义了一个叫作test的抽象方法。
第四,test方法描述了一个函数描述符,它可以接受一个Apple,并返回一个boolean。
最后,filter的任何实际参数都必须匹配这个要求。
这段代码是有效的,因为我们所传递的Lambda表达式也同样接受Apple为参数,并返回一个boolean。请注意,如果Lambda表达式抛出一个异常,那么抽象方法所声明的throws语句也必须与之匹配。
同一个Lambda表达式就可以与不同的函数式接口联系起来,只要它们的抽象方法签名能够兼容。比如,前面提到的Callable和PrivilegedAction,这两个接口都代表着什么也不接受且返回一个泛型T的函数。
特殊void兼容规则的例子:
// Predicate返回了一个boolean
Predicate<String> p = s -> list.add(s);
// Consumer返回了一个void
Consumer<String> b = s -> list.add(s);
3、方法引用