Lambda表达式简介
Java 8的最大变化是引入了Lambda表达式(Lambda 是希腊字母 λ 的英文名称)——一种紧凑的、传递行为的方式。编写Lambda表达式时,也会随之被编译成一个函数式接口。
Lambda 表达式
Lambda表达式的语法:
(argument-list) -> {body}
(参数列表) -> {若干语句;}
1) 参数列表: 可以为空,也可以非空.
2) 箭头: 它用来连接参数列表和方法体.
3) 方法体: 包含若干的表达式和语句.
几个示例:
// 1. 不需要参数,返回值为 21
() -> 21
// 2. 接收一个参数(数字类型),返回其5倍的值
x -> 5 * x
// 3. 接受2个参数(数字),并返回他们的和
(x, y) -> x + y
// 4. 接收2个int型整数,返回他们的乘积
(int x, int y) -> x * y
// 5. 接受一个Long对象,并在控制台打印,不返回任何值
(Long number) -> System.out.println(number)
// 6. 接受两个参数
(String aText,String bText) -> {
// some code here
return aText + bText;
}
函数式接口
在 Java 中,Marker(标记)类型的接口是一种没有方法或属性声明的接口,简单地说,marker 接口是空接口。相似地,函数式接口是只包含一个抽象方法声明的接口。
java.lang.Runnable 就是一种函数式接口,在 Runnable 接口中只声明了一个方法 void run(),相似地,ActionListener 接口也是一种函数式接口,我们使用匿名内部类来实例化函数式接口的对象,有了 Lambda 表达式,这一方式可以得到简化。
每个 Lambda 表达式都能隐式地赋值给函数式接口,例如,我们可以通过 Lambda 表达式创建 Runnable 接口的引用。
Runnable runnable = () -> System.out.println("hey,siri!");
当不指明函数式接口时,编译器会自动解释这种转化:
new Thread(
() -> System.out.println("hey,siri!")
).start();
因此,在上面的代码中,编译器会自动推断:根据线程类的构造函数签名 public Thread(Runnable r) { },将该 Lambda 表达式赋给 Runnable 接口。
一些常见的Lambda 表达式及其函数式接口:
Consumer<Long> c = (long x) -> { System.out.println(x) };
BiConsumer<Long, String> b = (Long x, String y) -> System.out.println(x + " : " + y);
Predicate<String> p = (String s) -> { s == null };
@FunctionalInterface 声明函数式接口
@FunctionalInterface 是 Java 8 新加入的一种接口,用于指明该接口类型声明是根据 Java 语言规范定义的函数式接口。Java 8 还声明了一些 Lambda 表达式可以使用的函数式接口,当你注释的接口不是有效的函数式接口时,可以使用 @FunctionalInterface 解决编译层面的错误。
定义:
@FunctionalInterface
public interface Pluggable {
void plug();
}
根据定义,函数式接口只能有一个抽象方法,如果你尝试添加第二个抽象方法,将抛出编译时错误。例如:
@FunctionalInterface
public interface Pluggable {
void plug();
void recharge();
}
使用例子:
@FunctionalInterface
public interface Pluggable {
void plug();
}
class PluggableTest {
public static void main(String[] args) {
PluggableTest.execute(() -> {
System.out.println("It is pluggable with lambda expression!");
});
PluggableTest.execute(new Pluggable() {
@Override
public void plug() {
System.out.println("It is pluggable with anonymous class!");
}
});
}
public static void execute(Pluggable pluggable) {
pluggable.plug();
}
}
Lambda 表达式与匿名类的区别
使用匿名类与 Lambda 表达式的一大区别在于关键词的使用。对于匿名类,关键词 this 解读为匿名类,而对于 Lambda 表达式,关键词 this 解读为写就 Lambda 的外部类。
Lambda 表达式与匿名类的另一不同在于两者的编译方法。Java 编译器编译 Lambda 表达式并将他们转化为类里面的私有函数,它使用 Java 7 中新加的 invokedynamic 指令动态绑定该方法。
(完)