可能很多人都听说过java8的新特性----Lambada表达式,但可能很多人都不知道Lambda表达式到底有什么用,下面我带大家理解一下Lambada表达式。
在平时的编程中,我们常常会用到匿名内部类,见下面代码:
package 示例;
import static org.junit.Assert.*;//
import org.junit.Test;
public class LambdaTest {
@Test
public void testOld1() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("原始方法使用匿名内部类");
}
}).start();
}
}
上述代码运用到了匿名内部类,但你们有没有发现,接口名和方法名在这段代码逻辑中是固定的,也就是说我们通过实现Runnable接口就必定实现父类接口中的run方法。写一万次上述代码,只有run方法内部的算法逻辑是改变的。
java8也就引入了一个新特性-----Lambda表达式
package 示例;
import static org.junit.Assert.*;
import org.junit.Test;
public class LambdaTest {
@Test
public void testNew1(){
/*此处用Lambda表达式,省略了接口名“new Runnable(){}”,以及接口中需要实现的方法名,以及修饰方法关键字(public void),只留下run方法用来传参数的“()”。因为run方法没有参数,所以括号中什么也没有 (这里的圆括号就是run方法的括号,只是省略了方法名)*/
new Thread(()->System.out.println("Lambda表达式")).start();
}
}
在上面的代码中,我们用Lambda表达式代替了传统的匿名内部类形式的Java代码,Lambda表达式如下:
()->System.out.println("Lambda表达式")
被替换的传统代码如下:
new Runnable(
public void run(){
System.out.println("匿名内部类");
}
)
(一)我们现在来看看为什么可以省略这些东西呢
(1)为什么可以省略接口名:
因为在Lambda表达式外面有new Thread()。而我们根据多线程的学习知道,Thread类的构造器如果只传入一个参数,那必定是Runnable接口实现类的实例。
public Thread(Runnable target)
所以编译器在编译的时候,是可以推断出来我们后面匿名内部类实现的接口是什么(Lambada表达式就是匿名内部类的精简写法),因此Lambda表达式将接口名省略。
(2)为什么可以省略接口中的方法名
通过上面我们知道了,编译器可以推导匿名内部类实现的接口名。那Runnable接口中只有一个抽象方法,因此编译器同样可以推导出实现类中的方法名。
(二)Lambda表达式的具体语法
语法:(参数列表)->{函数体};
注:Lambda表达式省略了匿名内部类的接口名、和方法名,目的就是让我们专注于接口方法的实现部分。
(1)参数列表规则
-
如果没有参数,直接用“()”表示。()不能省略。
-
如果只有一个参数,并且参数写了类型,则一定要加()
-
如果只写了一个参数,并且参数不写类型,那么这个参数外面不用加“()”。
- 如果有两个或多个参数,则“()”必须写。
(2)函数体规则
- 如果函数体只有一行,那么可以省略“{}”。
- 如果函数体有多行,则“{}”不能省略。
- 如果函数体有多行,并且该函数有返回值,则不能省略“return”关键字。
- 如果函数体是一行,并且函数有返回值,则必须省略“return”关键字(由编译器自己推导返回类型)
java8引入Lambda表达式的唯一目的就是简化函数式接口的使用。(暂时可以理解为简化匿名内部类的使用)
(三)Lambda表达式异常处理
- Lambda表达式产生的异常在函数体中try-catch。
- 在接口的抽象方法定义时,声明抛出异常。
(四)Lambda表达式使用场景(局限性)
由上面的的学习可知,Lambda表达式实际上就是匿名内部类的一种精简写法。在编译时还是会被推导为匿名内部类,说白了Lambda表达式就是一种“语法糖”。根据Lambda表达式省略接口名与方法名的原理可知,只有在编译器自身能够推导出匿名内部类实现的接口时,才能使用Lambda表达式。在能够推导出接口后,必须满足接口中只有一个抽象方法才能运用Lambda表达式。
补充说明:在Java中,通常将只有一个抽象方法的接口称为函数式接口,我们可以在接口上添加“@FunctionalInterface”标签,表明这是一个函数式接口。
总结
Java8新增的这一特性唯一的目的就是简化函数式接口的使用,它本身不是一个新的语法知识,底层实际上还是匿名内部类,所以学会灵活使用Lambda表达式,可以提高代码的开发效率,但在后期维护中降低了代码的可读性,博友们可以尝试一下这种“语法糖”。
下面是博主的其他文章,喜欢的博友点个关注,感谢您的支持。
JDK8以前匿名内部类访问局部变量为什么必须用final修饰
Validate插件的自定义表单校验入门(结合Ajax实现用户名的数据库查重)