文章目录
1. 前言
结合官方文档,我们来研究一下Lambda表达式到底是什么?
2. Lambda是什么??
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。
Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。
使用 Lambda 表达式可以使代码变的更加简洁紧凑。 — 菜鸟教程
看起来Lambda就是将函数作为参数传递进方法的表达式…那么这样做的好处是什么呢?
作为一种更紧凑的代码风格,使Java的语言表达能力得到了提升 ,JDK 也提供了大量的内置函数式接口供我们使用,使得 Lambda 表达式的运用更加方便、高效。
看起来像是个语法糖,使用了它能够高效地编写代码,接下来看看语法吧~
3. Lambda的语法
看起来并不是非常的复杂:由一个括号()->{};组成,圆括号中放参数,方括号中是表达式具体内容。
(parameters) -> expression // 如果表达式只有一行,那么花括号可以省略…甚至一个参数的时候圆括号也可以省略 parameters -> expression
或
(parameters) ->{ statements; }
以下是lambda表达式的重要特征:
(1)可选类型声明 :不需要声明参数类型,编译器可以统一识别参数值。
(2)可选的参数圆括号 :一个参数无需定义圆括号,但多个参数需要定义圆括号。
(3)可选的大括号 :如果主体包含了一个语句,就不需要使用大括号。
(3)可选的返回关键字 :如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定表达式返回了一个数值。
看几个菜鸟教程给的例子
- 不需要参数,返回值为 5
() -> 5
- 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
- 接受2个参数(数字),并返回他们的差值
(x, y) -> x – y
- 接收2个int型整数,返回他们的和
(int x, int y) -> x + y
- 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)
4. 如何使用Lambda表达式?
使用 Lambda 表达式主要作用于函数式接口,传入的表达式则是对接口中唯一的方法的实现。
(1) 什么是函数式接口?
一开始傻傻的以为,所谓“函数式接口”就是一个接口中只允许有一个方法。。其实是这样的:
函数式接口是除了Object提供的方法外,只包含一个抽象方法的接口。(当然JDK8允许的接口中的default以及static方法是可以有的…)
举个例子:下面这个就是一个函数式接口!
@FunctionalInterface
public interface LambdaTest {
static void say(){
System.out.println("这里是static方法");
}
void impl();
default void hi(){
System.out.println("这里是default方法");
}
}
哦对了,关于**@FunctionalInterface注解**,我们可以在接口上面加上这个注解来检查该接口是否为函数式接口,如果不是,那么注解会爆红,编译不通过。(下面就是把除了Object方法外的唯一方法impl()删掉,则注解爆红)
我们可以测试一下其他情况:
(1)如果有两个自定义的方法?不是接口函数
(2)一个自定义方法加几个Object方法?是接口函数
@FunctionalInterface注解,非必须,可不加。。主要作用还是用来检验是否为函数式接口用的。
既然Lambda表达式的主体我们知道了是"函数是接口",并且我们也研究了什么是函数是借口,下一步我们来看看,lambda表达式具体如何作用于函数式接口!
(2) lambda表达式具体如何作用于函数式接口?
如何作用于接口下面举个例子:
1.我们先创建一个函数式接口
2.在测试类中创建接口类的变量,并将接口中唯一抽象方法的具体实现利用Lambda表达式传入,使用变量调用这个传入了具体实现的唯一抽象方法。
finally:于是该抽象方法便按照Lambda中传入的具体实现执行了
当然这只是Lambda作用于函数是接口最简单的使用方法(因为这个抽象方法返回值是void),我们也可以试试具有返回值的抽象方法,以及具有参数的抽象方法,Lambda该如何作用其方法上?
传入实现类的表达式以及返回值**(一行的时候可以直接写返回值不写return,如果有多行表达式,需花括号不能省略,return也需要写)**
输出:
这样我们对Lambda表达式就基本掌握了
为了加深对Lambda表达式的印象,这里挑几段源码分析分析。
5. 源码中的Lambda是怎么用的?看几个例子加深理解!
在Spring框架中,AbstractBeanFactory类中
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
可以看到这里getSingleton方法,第二个参数传递的是一个函数式接口的实现细节
我们将这个Lambda表达式剥离出来单独看看,他想要按照Bean的名字以及Bean的定义信息,创建一个Bean,如果失败则把它干掉。
() -> {
try {
return createBean(beanName, mbd, args);
}catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
再来看看,这个Lambda表达式作用于什么函数式接口上?
因为这个Lambda表达式作为getSingleton的第二个参数传入,可以看到第二个参数是一个ObjectFactory
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
进入这个ObjectFactory,其中有一个唯一的抽象方法getObject,就是传给他的!
@FunctionalInterface
public interface ObjectFactory<T> {
/**
* Return an instance (possibly shared or independent)
* of the object managed by this factory.
* @return the resulting instance
* @throws BeansException in case of creation errors
*/
T getObject() throws BeansException;
}
那么这个T又是什么呢?参考我的另一篇文章: 添加链接描述
[暂时先记到这…有问题评论区探讨~peace!]