当我们创建新的线程时,我们可能习惯这么写:
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("test");
}
}).start();
}
在idea中使用java8及以上的版本,我们会发现new Runnable()这句代码变灰了,并带有如下警告:
Anonymous new Runnabel() can be replaced with lambda.
Alt + Enter快速优化后,我们可以发现原本六行的创建新线程代码变成了一行。
public static void main(String[] args) {
new Thread(() -> System.out.println("test")).start();
}
这么简洁的语法,得益于java8中新加入的特性lambda表达式。
以实现Runnable接口为例,我们看到了lambda表达式的用法:实现函数式接口。
所谓函数式接口,就是仅有一个抽象方法的接口(默认方法和静态方法不算)。
我们先来看一下lambda表达式的语法。
(参数) -> {方法体}
可以看到,lambda表达式的语法中,最具标志性的就是一个新的操作符 ->
.
左侧是参数列表,右侧是方法体内容。
我们来自定一个函数式接口实战操作一下
public class Main {
public static void main(String[] args) {
Test test = (String msg) -> {System.out.println(msg);} //实现函数式接口,实现其中的抽象方法
test.printMsg("test");
}
}
interface Test{
void printMsg(String msg);
default void defaultPrintMsg(String msg){} // 测试默认函数是否会导致函数式接口规则崩坏
}
运行后输出test。
lambda表达式的语法有如下几点特性:
可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
Test test1 = (String msg) -> {System.out.println(msg);}
Test test2 = (msg) -> {System.out.println(msg);}
可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
Test test3 = msg -> {System.out.println(msg);}
可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
Test test4 = msg -> System.out.println(msg);
可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
public class Main {
public static void main(String[] args) {
ReturnTest returnTest = (a, b) -> a + b; // 不需要显式return
int c = returnTest.plus(1, 2);
System.out.println(c);
}
}
interface ReturnTest{
int plus(int a, int b);
}
变量作用域 lambda 表达式只能引用标记了 final 的外层局部变量。
当使用了非final修饰局部变量的lambda表达式被return到其他方法中使用时,原方法的局部变量已被销毁,无法访问。若使用了final修饰局部变量,该变量会被放到方法区中,不随着方法结束而销毁,故可以继续访问。
@FunctionalInterface注解
用在接口声明处,用于编译级检测,当你声明的接口不符合函数式接口的约束时,编译器会报错。