什么是lambda表达式
lambda表达式的本质
lambda表达式是一种匿名函数,匿名函数是函数定义不绑定到任何标识符的函数。所以lambda表达式本质上是函数,lambda expression, function literal, lambda abstraction 本质上都是匿名函数。
lambda表达式的样子
看图很清楚,主要由三部分组成:函数签名、lambda操作符、函数主体;lambda操作符将函数签名和函数主体分开。
使用lambda表达式时,看lambda表达式定义,即接收多少个参数,每个参数是什么类型;返回多少个参数,每个参数是什么类型。需要关注lambda表达式实现细节时,才需要看函数主体。
lambda表达式常见形式
Runnable noArguments = () -> System.out.println("Hello World");
ActionListener oneArgument = event -> System.out.println("button clicked");
Runnable multiStatement = () -> {
System.out.print("Hello")
System.out.println(" World")
};
BinaryOperator<Long> add = (x, y) -> x + y;
BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;
上述源码对应:
- 无参数
- 单个参数
- 无参数,多行写法
- 两个参数
- 两个参数,显式说明类型
单看() -> System.out.println("Hello World");
是无法得出此lambda表达式的具体类型的,在不同环境下,此表达式的类型也不同;实际上,lambda表达式的类型依赖于上下文环境,是由编译器推断出来的;所以我们更在意lambda表达式的目标类型——Lambda表达式所在上下文环境的类型。
java8如何支持lambda,在哪儿使用
java8仍然是面向对象语言,在面向对象语言中,函数被放在类、抽象类或者接口中,lambda表达式作为函数也要放在某个地方,Oracle工程师对Java进行微调,引入函数接口的概念,lambda表达式就被放在函数接口中,只有函数接口存在的地方可以使用lambda表达式。
函数接口
只有一个抽象方法的接口被称为函数接口,函数接口可以使用@FuctionalInterface
注解,也可以不使用。
函数接口中我们要注意的就是这单一函数接口所明确的lambda表达式的签名,其它并不重要。当使用的Lambda表达式和函数接口中函数类型兼容时,即可使用此Lambda表达式。在函数接口中为函数起一个有意义的名字,可以增加代码易读性,便于更透彻地理解参数的用途。
函数接口的图形表示
接口 | 参数 | 返回类型 |
---|---|---|
Predicate<T> | T | boolean |
Consumer<T> | T | void |
Function<T, R> | T | R |
Supplier<T> | None | T |
UnaryOperator<T> | T | T |
BinaryOperator<T> | (T, T) | T |
使用函数接口的图形表示可以很明确地知道函数接口的输入和输出,进而了解函数接口的用途。
函数接口的图形表示,使用指向函数的箭头表示参数,从函数射出的箭头表示返回。
接口 | 参数 | 返回类型 |
---|---|---|
Predicate<T> | T | boolean |
Consumer<T> | T | void |
Function<T, R> | T | R |
Supplier<T> | None | T |
UnaryOperator<T> | T | T |
BinaryOperator<T> | (T, T) | T |
上述内置函数接口的图形表示如下图:
查看Predicate的图形表示,知道其输入是任意的T类型,返回是boolean类型,函数的作用通过其名字Predicate知道这个函数是一个断言函数,对输入任意一个类型T,断定其真假,断定的逻辑就由实现它的函数,或者与其兼容的lamba表达的主体决定。