Hi,你的Lambda表达式掉了

2024-02-09 01:48
文章标签 表达式 lambda hi

本文主要是介绍Hi,你的Lambda表达式掉了,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

写在之前

用了一段时间的Lambda 表达式,但是感觉都还是有点不系统,每次都是想到要用再去找。这里做一个总结,希望对大家能有所帮助。

内容结构

基本内容如下:

  1. Lambda 是什么
  2. Lambda 表达式实现原理
  3. Lambda 表达式语法格式

1 Lambda 是什么

基本概念

Lambda的基本语法格式;

//parameters -> expression
(int num) -> {return num++;}

Lambda表达式作为Java8的重要新特性,第一次出现是2014年了。但是因为技术更新的延迟和项目的历史原因,真正完全使用这个新特性还有一定的时间滞后。

那么首先来看看Java8为什么要引入Lambda的新特性呢?

Lambda是函数式编程的 λ演算的产物,百度一下,Lambda这个单词的解释是匿名函数(并不是闭包)。在Java中一切都是对象,那么为什么要引入这个匿名函数呢?这还要从函数式编程开始说起。

函数式编程

我们日常在Java中都是面向对象编程,这种叫做命令式编程,也就是一次方法调用是给对象发出一条指令,告诉对象该执行什么操作了。

而函数式编程的世界里,一切都是数学函数。函数式编程是通过某种语法或者调用函数进行编程。所以函数式编程是告诉你该做什么,而命令式编程告你该怎么做。这样的区别引发的结果就是函数式编程更能体现出逻辑含义,而且代码更加简洁,这也就是使用函数式编程的原因之一。

在命令式编程到函数式编程的转变过程中,除了语法上的变化,更重要的是思考方式的转变。

2 Lambda表达式实现原理

首先声明的是Jvm对Lambda表达式是无感知的,因为Lambda表达式作为一种语法糖,在类编译阶段已经将Lambda的语法糖编译为实际的实现结果,没有匿名函数,没有Lambda表达式,对于Jvm来说只知道这是一堆可以执行的字节码。

匿名内部类

在Java中提到Lambda表达式,一定再提到另外一个概念,匿名内部类。

    @Testpublic void runnableTest() {//普通语法Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("我是普通语法线程");}};runnable.run();System.out.println("**************************");}

上面这段代码使用匿名内部类的方式定义了一个执行线程,在编译阶段Jvm会创建一个类文件,所以匿名内部类的定义虽然和一般的类不同,但是本质没有区别。

下面是通过Lambda表达式定义一个执行线程,可以对比一下和匿名内部类的区别。

		@Testpublic void runnableTest() {//Lambda语法线程Runnable runnable1 = () -> System.out.println("我是Lambda语法线程");runnable1.run();}        

虽然看上去类似,但是Lambda的底层实现原理并不是使用匿名内部类。Scala之前版本是使用匿名内部类来实现Lambda表达式,但是在后续版本更新中,也是通过匿名函数的方式来实现了。

为什么不是使用匿名内部类

首先,对于匿名内部类,编译器首先会创建一个类文件,如果匿名内部类很多,那么再类加载过程中就会对这些文件进行验证,导致影响应用的启动性能。加载类文件也是一个耗时过程,涉及到jar文件的解压、磁盘的IO,这些也会影响加载性能。

而且,如果Lambda表达式使用匿名内部类实现,那么每个Lambda表达式都会编译成一个类文件,这样无论是类文件加载到元空间,还是创建类的对象,都会占用内存。

同时,如果使用匿名内部类实现,那么Lambda表达式会按照匿名内部类的字节码机制进行编译,这样以后如果对Lambda表达式优化的话,那么是相当于要在匿名内部类的限制下了。

所以Lambda实际使用invokedynamic字节码指令来生成Lambda字节码。首先生成一个Lambda工厂,当实际调用时返回Lambda表达式转化成的函数式接口实例。

将Lambda表达式的方法体转换成方法供invokeddynamic指令调用。

3 Lambda 语法格式

函数式接口

Java中定义了很多函数式接口,特点就是接口中只有一个方法。

  1. Runnable
  2. Consumer
  3. Function
  4. Predicate
  5. Supplier

还有其他的函数式接口,同时也可以自定义函数式接口,Java提供了一个@FunctionalInterface注解,通过这个注解可以帮助验证定义的接口是否是函数式接口,如果不符合规则,编译阶段就会报错。

@FunctionalInterface
public interface LambdaInterface {void invoke();//如果再有这个定义,编译报错//void anotherInvoke();
}

Lambda表达式只支持函数式接口,这一点需要注意,下面通过实现以上函数式接口,说明一下Lambda的基本语法格式。

语法格式一:无参数,无返回值

	@Testpublic void lambdaFormatTest1() {//普通语法Runnable runnable = new Runnable() {@Overridepublic void run() {System.out.println("我是普通语法线程");}};runnable.run();System.out.println("**************************");//语法格式一:无参数,无返回值Runnable runnable1 = () -> System.out.println("Lambda表达式 语法格式一");runnable1.run();}

语法格式二:一个参数,无返回值

	@Testpublic void lambdaFormatTest2() {Consumer<String> consumer = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};consumer.accept("Consumer 原始语法格式");System.out.println("**************************");//语法格式二:一个参数,无返回值Consumer<String> consumer1 = (String str) -> System.out.println(str);consumer1.accept("Lambda表达式 语法格式二");System.out.println("**************************");}

语法格式三:通过类型推断,省略参数类型

	@Testpublic void lambdaFormatTest2() {Consumer<String> consumer = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};consumer.accept("Consumer 原始语法格式");System.out.println("**************************");//语法格式三:通过类型推断,省略参数类型Consumer<String> consumer2 = (str) -> System.out.println(str);consumer2.accept("Lambda表达式 语法格式三");
}

语法格式四:一个参数省略

	@Testpublic void lambdaFormatTest2() {Consumer<String> consumer = new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}};consumer.accept("Consumer 原始语法格式");System.out.println("**************************");//语法格式四:一个参数,省略()Consumer<String> consumer3 = str -> System.out.println(str);consumer3.accept("Lambda表达式 语法格式四");}

语法格式五:两个或以上参数,多条执行语句,有返回值

	@Testpublic void lambdaFormatTest3() {//普通语法Comparator<Integer> comparator = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1.compareTo(o2);}};System.out.println(comparator.compare(1, 2));System.out.println("**************************");//语法格式五:两个或以上参数,多条执行语句,有返回值Comparator<Integer> comparator1 = (Integer o1, Integer o2) -> {System.out.println("第一个参数:" + o1);System.out.println("第二个参数:" + o2);return o1.compareTo(o2);};System.out.println("Lambda表达式 语法格式五: " + comparator1.compare(1, 2));
}

语法格式六:一条执行语句,有返回值

	@Testpublic void lambdaFormatTest3() {//普通语法Comparator<Integer> comparator = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1.compareTo(o2);}};System.out.println(comparator.compare(1, 2));System.out.println("**************************");//语法格式六:一条执行语句,有返回值Comparator<Integer> comparator2 = (o1, o2) -> o1.compareTo(o2);System.out.println("Lambda表达式 语法格式六: " + comparator2.compare(1, 2));}

以上介绍了Lambda的6中语法格式,实际使用中,Lamba经常和Stream流结合使用,变化可能更丰富些,但基本也在这6中情况中。

最后

本篇主要介绍了Lambda表达式是什么,实现原理,基本使用。其实还有很多方面没有说明,例如异常处理、并发处理等。后续还会对Lambda相关的内容继续学习,补充内容。

而且Lambda和Stream的结合是日常开发中非常高频的使用场景,Stream也是Java8的亮瞎眼新特性之一,接下来会总结一下Stream的相关内容。

这篇关于Hi,你的Lambda表达式掉了的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/692807

相关文章

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

hihocoder1114 小Hi小Ho的惊天大作战:扫雷·一

1114 : 小Hi小Ho的惊天大作战:扫雷·一 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 故事背景:密室、监视器与充满危机的广场 “我们还是循序渐进,先来考虑这样一个简单化问题:”小Hi思索片刻,道:“在一个大小为2*N的广场,其中第一行里的某一些格子里可能会有至多一个地雷,而第二行的格子里全都为数字,表示第一行中距离与这个格子不超过2的格子里总共有多少个

如何掌握面向对象编程的四大特性、Lambda 表达式及 I/O 流:全面指南

这里写目录标题 OOP语言的四大特性lambda输入/输出流(I/O流) OOP语言的四大特性 面向对象编程(OOP)是一种编程范式,它通过使用“对象”来组织代码。OOP 的四大特性是封装、继承、多态和抽象。这些特性帮助程序员更好地管理复杂的代码,使程序更易于理解和维护。 类-》实体的抽象类型 实体(属性,行为) -》 ADT(abstract data type) 属性-》成

Java基础回顾系列-第三天-Lambda表达式

Java基础回顾系列-第三天-Lambda表达式 Lambda表达式方法引用引用静态方法引用实例化对象的方法引用特定类型的方法引用构造方法 内建函数式接口Function基础接口DoubleToIntFunction 类型转换接口Consumer消费型函数式接口Supplier供给型函数式接口Predicate断言型函数式接口 Stream API 该篇博文需重点了解:内建函数式

C语言程序设计(数据类型、运算符与表达式)

一、C的数据类型 C语言提供的数据类型: 二、常量和变量 2.1常量和符号常量 在程序运行过程中,其值不能被改变的量称为常量。 常量区分为不同的类型: 程序中用#define(预处理器指令)命令行定义变量将代表常量,用一个标识符代表一个常量,称为符合常量。 2.2变量 变量代表内存中具有特定属性的一个存储单元,用来存放数据,在程序运行期间,这些值是可以 改变的。 变

JavaSE(十三)——函数式编程(Lambda表达式、方法引用、Stream流)

函数式编程 函数式编程 是 Java 8 引入的一个重要特性,它允许开发者以函数作为一等公民(first-class citizens)的方式编程,即函数可以作为参数传递给其他函数,也可以作为返回值。 这极大地提高了代码的可读性、可维护性和复用性。函数式编程的核心概念包括高阶函数、Lambda 表达式、函数式接口、流(Streams)和 Optional 类等。 函数式编程的核心是Lambda

逻辑表达式,最小项

目录 得到此图的逻辑电路 1.画出它的真值表 2.根据真值表写出逻辑式 3.画逻辑图 逻辑函数的表示 逻辑表达式 最小项 定义 基本性质 最小项编号 最小项表达式   得到此图的逻辑电路 1.画出它的真值表 这是同或的逻辑式。 2.根据真值表写出逻辑式   3.画逻辑图   有两种画法,1是根据运算优先级非>与>或得到,第二种是采

将浮点型算式的中缀表达式转换成后缀表达式并算出式子结果

最近因为需要了解如何将在Win应用程序控制台输入的算式表达式转化成其后缀表达式的算法,所以在网上搜索了一下,看到许多人的程序都只是对应于运算数在0~9的范围内的整型运算式,所以自己就写了一个可以计算浮点型算式的程序,一下是运行时的截图: 式子中的a,b,c是可供用户自行输入的变量。 首先,我先对输入的运算符进行了简单的合法性判断,我的判断代 码如下: //函数的传入参