源码元宇宙-lambda表达式底层执行解析

背景

3月28日那天,咱们 用户群 里,朋友让我写篇lambda表达式的底层执行解析。拖了快20天了,今天就来聊聊这个问题。

深入理解函数式编程里讲到lambda表达式本质是一个匿名的内联函数。不从Java角度,Lambda本身是计算机编程语言,Lambda 表达式是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。那篇文章讲解了匿名内部类与函数式编程怎么转换,怎么debug调试。

对面试而言,这些内容足够了。朋友提出想了解lambda表达式的底层执行解析。说明是真的对技术有追求,是把问题思考细化了,这个是很赞的。

面试官问我:你做事仔细吗?》一文中,我提出了仔细意识的重要性。大家想想,咱们上高三的时候,一般的学生是不是所有课本上讲的数学题都会做?那为什么考满分的却寥寥无几。老师告诉我们这不是马虎不马虎的事情,就是能力的差距。

能力的差距就在于把问题考虑仔细周全的能力。互联网的上半场,IT能力刚起步,就好像教育水平低的学校,能把课学明白的就不多。而互联网的下半场好比是重点高中,一个差生有可能是小学的时候的班长。学习能力都没有问题,想达到更高的深度和广度靠的就是把问题细化分解这种“额外”能力的差距。

总结来说:越是基础的知识,越需要沉下心,将问题细化。

函数式接口

Lambda是函数式编程思想的一个重要体现,让我们不用关注是什么对象,而是更关注我们对数据进行了什么操作。在函数式编程思想中,函数是"第一等公民"。所谓"第一等公民"(first class),指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值。

Lambda表达式的入参都是函数,所以咱们先来看看函数在Java中的定义。

4a33031e115070c555571d4f18add530.png

匿名内部类,类是使用时实现的,在Lambda表达式中,入参都是函数接口来定义的,函数接口大多都带有 @FunctionalInterface 注解。先看看这个注解的定义。

/**
 * An informative annotation type used to indicate that an interface
 * type declaration is intended to be a <i>functional interface</i> as
 * defined by the Java Language Specification.
 *
 * Conceptually, a functional interface has exactly one abstract
 * method.  Since {@linkplain java.lang.reflect.Method#isDefault()
 * default methods} have an implementation, they are not abstract.  If
 * an interface declares an abstract method overriding one of the
 * public methods of {@code java.lang.Object}, that also does
 * <em>not</em> count toward the interface's abstract method count
 * since any implementation of the interface will have an
 * implementation from {@code java.lang.Object} or elsewhere.
 *
 * <p>Note that instances of functional interfaces can be created with
 * lambda expressions, method references, or constructor references.
 *
 * <p>If a type is annotated with this annotation type, compilers are
 * required to generate an error message unless:
 *
 * <ul> * <li> The type is an interface type and not an annotation type, enum, or class.
 * <li> The annotated type satisfies the requirements of a functional interface.
 * </ul> *
 * <p>However, the compiler will treat any interface meeting the
 * definition of a functional interface as a functional interface
 * regardless of whether or not a {@code FunctionalInterface}
 * annotation is present on the interface declaration.
 *
 * @jls 4.3.2. The Class Object
 * @jls 9.8 Functional Interfaces
 * @jls 9.4.3 Interface Method Body
 * @since 1.8
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}

这个接口的注释说明了函数接口的要点:

1)函数接口有且只有一个抽象方法

4775b7fc445560efd181a5d76d26383b.png

2)可以有其他default 实现的方法,这不违背有且只有一个抽象方法的原则,因为实现了就不是抽象的

91f05b850008ce5492783f7d552d9149.png

3)可以有额外的 java.lang.Object 的 public 的抽象类,这不违背有且只有一个抽象方法的原则,因为 Object 或者其他的地方 已经实现了这个方法

82555db743c14aad70545a178ae7851d.png

4)函数式接口可以通过lambda表达式、方法引用或者构造方法引用来创建实例

b5f616992b740932a82ffc97136f0c55.png

5) 如果加上了 @FunctionalInterface 注解,编译器就会校验是否符合下面规范,不符合就会报编译错误:

规范规定此注解只能加在接口上,不能加在注解类型、枚举类型和类上,并且这个接口还要满足上面那4个条件。

6)满足上面5个条件,即使不加 @FunctionalInterface 注解,也是函数式接口

咱们来动手实践一下,写个小例子运行一下:

dc13fd0ecdebfc4778db364cb19f174e.png

我们定义了一个接口的lambda表达式形式的实现,发现这个实现是Java自己的实现类,类名是Java自己生成的匿名内部类,其父类是Object,实现了YunaInterface这一个接口。

本系列的所有代码文字在 https://github.com/xiexiaojing/yuna 里可以找到。

forEach方法引用lambda表达式

先看一个简单的例子,一个list进行forEach:

f2ec7fd9b1fc4ebf50e0d3c62abfebbe.png

跟进源码里看一看:、

ec21276710f4b71ca1f985de6f16b104.png

这里就通过lambda表达式把实现了Consumer接口的行为动作传给了forEach方法。

咱们来看一看Consumer接口:

bd48565474d0713e9fe3e65806ae5f97.png

首先还是来翻译一下接口说明:

这个函数代表了一个操作,这个操作只接受一个参数并且不返回结果。但是和大多数函数式接口不同,它会产生副作用。

这段说明很好的诠释了类名Consumer和accept方法:只accept一个参数T,并且消费掉了不会返回结果。forEach方法就是对下面匿名内部类的简写:

0f4844e6c143991c2af409f853bb1bbb.png

Alter+Enter快捷键可以对其进行化简,最简的写法是下面方法引用的形式:

a5674e625b548903c74b84e992a0d27b.png

大家可能注意到Consumer里有个带有默认实现的andThen方法,这个方法有需要的时候这样可以使用:

45d14f22afae0911dcfc2b995fd0ff40.png

总结

本文说明了函数式接口特性和作用,并在此基础上介绍了forEach这个方法的底层实现。相信大家看了文章应该对底层执行怎么去深入了解有了思路和方法,可以自己去研究其他的函数了。

编程一生

因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。

想知道自己错过了哪些更新,可参考我不定期更新的《系列文章分类汇总

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值