Lambda表达式是Java 8中的新特性,是Java迈入函数式编程的第一步,它不依赖于任何类而被创建,它能像对象一样被传递和按需执行。
Lambda与单方法接口
函数式编程常被用于实现事件监听器,事件监听器在java中常被定义为一个接口,该接口通常只有一个方法:
1 | public interface StateChangeListener { |
这个接口定义了一个方法,期望状态发生改变时被调用。
Java 7中,必须实现此接口才能监听状态更改。假设有一个类StateOwner
,它能注册状态事件监听器:
1 | public class StateOwner { |
Java 7中,可以使用匿名类实现接口添加事件监听器:
1 | StateOwner stateOwner = new StateOwner(); |
而在Java 8中,可直接使用lambda表达式添加事件监听器:
1 | StateOwner stateOwner = new StateOwner(); |
下面一行就是lambda表达式:
1 | (oldState, newState) -> System.out.println("State changed") |
lambda表达式与addStateListener()
方法参数的参数类型相匹配,如果lambda表达式与参数类型相匹配(本例中为StateChangeListener),那么lambda表达式将转换为实现与该参数相同的接口的函数。
Java lambda表达式只能用于与之匹配的类型为单一方法的接口。在上面的例子中,lambda表达式被用作类型为StateChangeListener
的方法的参数。StateChangeListener
只有一个方法,因此lambda表达式与该接口成功匹配。
Lambda与接口之间的匹配
单一方法接口有时候也被称之为函数接口。函数接口匹配lambda分为以下几步:
确保接口只有一个方法
lambda表达式参数匹配函数接口方法参数
lambda返回值类型匹配函数接口方法返回值类型
Lambda表达式类型推导
Java 8之前匿名实现也需要指定具体的接口:
1 | stateOwner.addStateListener(new StateChangeListener() { |
下面使用lambda表达式,未提及StateChangeListener
接口,但是编译器可根据addStateListener
方法声明推断出参数类型:
1 | stateOwner.addStateListener( |
lambda表达式中的参数类型也可以类型推导,例如(oldState, newState)
可通过onStateChange()的方法声明推导而出。
Lambda表达式参数
Java lambda表达式实际上类似于方法,因此lambda表达式可以像方法一样使用参数。 前面显示的lambda表达式的(oldState, newState)部分指定了lambda表达式所需的参数。这些参数必须与单个方法接口上方法的参数相匹配。在这种情况下,这些参数必须与StateChangeListener接口的onStateChange()方法的参数匹配:
1 | public void onStateChange(State oldState, State newState); |
至少lambda表达式和方法中的参数数量必须匹配。其次,如果在lambda表达式中指定了任何参数类型,则这些类型也必须匹配。(类型放入lambda表达式参数,本文稍后会介绍)
无参数
方法无参数,可以写成这样:
1 | () -> System.out.println("Zero parameter lambda"); |
一个参数
方法一个参数:
1 | (param) -> System.out.println("One parameter: " + param); |
一个参数的时候,亦可以省略圆括号:
1 | param -> System.out.println("One parameter: " + param); |
多个参数
1 | (p1, p2) -> System.out.println("Multiple parameters: " + p1 + ", " + p2); |
参数类型
如果编译器无法从lambda匹配的函数接口方法中推断出参数类型,那么为lambda表达式指定参数类型有时可能是必需的,这种情况下编译器会提示。Lambda表达式指定参数类型:
1 | (Car car) -> System.out.println("The car is: " + car.getName()); |
如你所见,明确为car指定类型Car
。
Lambda函数体
Lambda表达式body在 “->” 右侧被指定,即类似于方法体:1
(oldState, newState) -> System.out.println("State changed")
如果需要多行,使用{}括起来:
1 | (oldState, newState) -> { |
Lambda返回值
Lambda表达式也可以有返回值,使用return语句即可:
1 | (param) -> { |
简短的形式:
1 | (a1, a2) -> { return a1 > a2; } |
等价于:
1 | (a1, a2) -> a1 > a2; |
用作对象
A Java lambda expression is essentially an object. You can assign a lambda expression to a variable and pass it around, like you do with any other object. Here is an example:
1 | public interface MyComparator { |
1 | MyComparator myComparator = (a, b) -> a > b; |
第一个代码块显示了lambda表达式实现的接口。 第二个代码块显示了lambda表达式的定义,lambda表达式如何分配给变量,最后是如何通过调用它实现的接口方法来调用lambda表达式。
集合示例
1 | // 迭代List |
扩展阅读,Java8 lambda表达式10个示例
参考:
Java Lambda Expressions,Jakob Jenkov