Lambda表达式的使用、简写与原理深入理解

简介: Lambda表达式的使用、简写与原理深入理解

jdk8之所以引入Lambda表达式,是受到函数式编程的启发,将其以一种特殊的方式引入至java的面向对象编程中。 好处是在很多场景下可以大大简化编程,然而其引入的代价则是 java编译器 和 jvm虚拟机都需要做额外的工作以适应这种新的“函数式”编程语法。

在java编程中,有些一次性临时使用的对象方法,我们可以使用匿名内部类的方式来进行简化。Lambda表达式的一个核心想法就是,借用函数式编程思想和语法进行更彻底的简化,即只需要在代码中说明要做什么即可,编译器可以自动进行类、对象方法中的匹配,不需要再写额外的 new overwride 等等冗余的代码。(函数式编程:别给我扯那些那些类模板、对象属性方法啥的,直接告诉我要做什么,好吗?)

一 Lambda表达式初体验

在上面的例子中,直观的能体会Lambda表达式的作用。简化了什么内容呢?

new 关键词、匿名内部类实现的接口名称、方法签名 、@Override 多余的{} ; 等。

这种写法实在是非常清爽。这能够感受到Lambda表达式的简化,其实这也是Lambda表达式最终极的简化形态。

二 原理深入

那么其中的原理是什么呢?

为什么仅仅只需要声明“做什么事情”即可让编译器无歧义的理解代码呢?

这其中编译之后的class文件是如何的呢?

在jvm层面是否违背了面向对象调用方法运行呢?jvm运行的时候又是如何的呢?

从匿名内部类开始理解

我们可以从匿名内部类开始理解。在面向对象编程过程中我们往往是将我们要做的事情封装在一个方法中,使用方法之前可能要通过对象来进行调用,而要产生对象则必须通过类模板来进行创建,其中经历了两次包装。而匿名内部类则让我们免于写类模板,减少了一次复杂的包装。先看看匿名内部类的原理:

package org.example.test;


public interface MyInterface {
    public abstract void run(String str);
}
package org.example.test;

public class AnonymousTest {
    public static void main(String[] args) {
        test(new MyInterface() {
            @Override
            public void run(String str) {
                System.out.println(str);
            }
        });
    }

    public static void test(MyInterface oneObject){
        oneObject.run("hello");
    }
}

定义MyInterface,同时AnonymousTest类中的test方法接收一个MyInterface的实现对象,该实现对象采用匿名内部类的写法。

编译AnonymousTest,输出如下,其中发现多了一个AnonymousTest$1.class文件。

反编译查看AnonymousTest和AnonymousTest$1.class。

发现了一些端倪。猜测如下:

编译器帮我们自动生成了一个类,且自动实现了MyInterface接口重写了run方法,方法体的内容就是我们在匿名内部类中重写的方法。

AnonymousTest中main方法中test方法调用时,传递了一个对象,这个对象理应是AnonymousTest$1对象,不过这个名字好像不对(猜测是反编译工具的一些处理不够完善,不过这个“new 1()”倒是可以猜测到一些端倪。)

想进一步验证,上字节码!!!

AnonymousTest的main方法和test方法字节码解读:

从main方法的第0~4行中发现,的确是新建了一个AnonymousTest$1对象并执行了初始化,第7行中将刚刚创建出来的AnonymousTest$1对象的引用传递给test方法,调用结束后直接返回。

test方法:第0行将main方法传递进来的AnonymousTest$1对象的引用入操作数栈,第1行加载“hello”字符串,第3行以多态的形式调用MyInterface接口中的run方法,也就是动态调用,程序执行的过程中将会调用AnonymousTest$1对象的run方法。

再看AnonymousTest$1对象的run方法,将方法入参(String str)放入操作数栈,执行打印控制台方法。

完美!!! 到此分析结束(字节码yyds)。

总结:

匿名内部类的确是编译器帮我们自动生成了一个匿名类(这个匿名只是相对于程序员而言的,相对于编译器和jvm是有名字的,该类为xxx$x的格式。其中xxx为匿名内部类所在类的类名,x表示是这个类中的第几个类,从1开始(很显然不能从0开始,因为0一般表示“本”“自己”的意思,这个序号不能分配给其他类也是避免引起混淆,也可以类比java方法中的局部变量表中的索引0代表本对象的引用))。

编译器会将原始匿名内部类的写法转换为标准的传递对象引用的写法。然后交由jvm执行。

很显然,匿名内部类只是一个语法层面的优化,为了避免程序员多写一个类,创造了一种新的语法,然后将创建类的过程交给了编译器。对于jvm来说,其实并没有发生任何的变化。最终的结果就是程序员少写了一点代码,编译器做了一些额外的工作,总工作量其实并没有减少。(不过只要程序员写得少了,那就有这样做的必要,毕竟编译器做额外的重复工作并无所谓。)


目录
相关文章
|
计算机视觉
YOLO 目标检测 识别框不显示文字标签(已解决)
YOLO 目标检测 识别框不显示文字标签(已解决)
|
弹性计算 数据可视化 Ubuntu
基于阿里云ECS搭建FISCO-BCOS区块链
用ubuntu操作系统下的ECS搭建FISCO-BCOS节点,开发区块链网络
基于阿里云ECS搭建FISCO-BCOS区块链
|
传感器 人工智能 自动驾驶
智慧城市中的智能交通系统:缓解拥堵与提升出行效率
【9月更文挑战第16天】随着城市化进程加快,交通拥堵和污染等问题日益严重,成为制约城市发展的瓶颈。为此,智慧城市应运而生,其中智能交通系统(Intelligent Traffic System, ITS)作为核心部分,正逐渐成为缓解交通拥堵、提升出行效率的关键力量。本文将探讨智能交通系统如何通过信号优化、智能导航及公交调度等策略,结合实时路况监测与自动驾驶技术,为城市交通带来革命性变革。未来,随着技术进步和政策支持,智能交通系统将进一步智能化并与智慧城市其他系统深度融合,共同推动城市的可持续发展。
1487 17
|
传感器 数据可视化 JavaScript
状态机(State Machines):理解、设计和应用有限状态机
状态机(State Machines)是一种强大的计算模型和设计工具,用于建模和控制有限状态的系统和行为。无论是在软件开发、自动化控制、游戏设计还是其他领域,状态机都发挥着关键作用。本博客将深入探讨状态机的概念、工作原理以及如何在不同应用中设计和应用它们。
9128 0
|
Rust 并行计算 JavaScript
函数式编程:革命性的编程范式
函数式编程:革命性的编程范式
|
存储 分布式计算 Hadoop
【Hadoop】HDFS 读写流程
【4月更文挑战第9天】【Hadoop】HDFS 读写流程
|
网络协议 vr&ar 网络架构
【华为数通HCIP | 网络工程师】821刷题日记-BFD和VRRP 及重点(2)
【华为数通HCIP | 网络工程师】821刷题日记-BFD和VRRP 及重点(2)
1553 0
|
网络协议 C++ Docker
Docker pull拉取镜像报错“Error response from daemon: Get "https://registry-1.docker.io/v2”解决办法
Docker pull拉取镜像报错“Error response from daemon: Get "https://registry-1.docker.io/v2”解决办法
53876 1
|
Arthas Java 测试技术
阿里巴巴开源的15个顶级Java项目
上个周末抽时间整理了一些阿里开源的一些 Java 开源项目,希望对大家有帮助!这篇文章收录的所有开源项目都是还在继续维护并且可以使用的。
|
Java uml
liteflow学习二
liteflow学习二
518 0