Java8新特性 ----- Lambda表达式和方法引用/构造器引用详解

前言

在讲一下内容之前,我们需要引入函数式接口的概念

什么是函数式接口呢?

函数式接口:有且仅有一个抽象方法的接口

java中函数式编程的体现就是Lambda表达式,你可以认为函数式接口就是适用于Lambda表达式的接口.

也可以加上注解来在编译层次上限制函数式接口

  • @Functionallnterface
  • 放在 接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败
  • 注:自定义的函数式接口可以加上这个表示是函数式接口,不加也可以,但是建议添加

常见的函数式接口有如下四种

接口                                 抽象方法
Consumer<T> 消费型接口           void accept(T t)
Supplier<T> 供给型接口           T get()
Function<T>函数型                R apply(T t)
Predicted<T>判断型接口           boolean test(T t)

以下对Lambda表达式的说明都是基于函数式接口的

为什么需要Lambda表达式?

本身我们最原始的方法定义类来实现接口,在用类来实例化对象调用方法显得冗余且重,我们简化到匿名内部类的时候也显得冗余,主要目的是为了简化代码,并提供更加简洁和灵活的函数式编程方式。也与后面要说的stream api有关,这里不做过多赘述.

1.Lambda表达式

Lambda表达式的本质其实是一个接口实现类的对象,也是一个匿名函数.

下面我们就谈谈几种lambda表达式的应用场景

1.实现Runnable接口,注意此处不涉及到线程!!

Lambda表达式的思想就是能省略的就省略,不产生歧义即可

于是就有了这样的写法

 @Testpublic void test1(){//语法格式1:无参数,无返回值Runnable r1 = new Runnable() {@Overridepublic void run() {System.out.println("我爱北京天安门");}};r1.run();System.out.println("*******************");Runnable r2 = ()->{ System.out.println("我爱北京天安门");};r2.run();}

2.当lanbda表达式中的参数类型确定时,参数类型也可以省略

 @Testpublic void test3(){//数据类型可以省略,因为可以由编译器进行推断Consumer<String> con1 = (String s)->{System.out.println(s);};con1.accept("如果大学可以重来,你最想重来的事是啥?");System.out.println("****************");Consumer<String> con2 = (s)->{System.out.println(s);};con2.accept("如果大学可以重来,你最想重来的事是啥?");}

3.只有一个参数的时候,小括号可以省略

 @Testpublic void test5(){//当只有一个参数的时候,参数的小括号可以省略Consumer<String> con1 = s->{System.out.println(s);};con1.accept("世界那么大,我想去看看");}

4.只有一条语句时,return语句和大括号可以省略(必须一起省略)

         Comparator<Integer> com1 = (o1,o2) ->{return o1.compareTo(o2);};System.out.println(com1.compare(12,6));System.out.println("***********************");Comparator<Integer> com2 = (o1,o2) -> o1.compareTo(o2);

总结:

格式

->:箭头操作符
->的左边:Lambda形参列表:对应着要重写的接口中要重写的形参列表
->的右边:Lambda体,对应着接口的实现类要重写的方法体
Lambda形参列表 ->Lambda体

细节注意

->的左边 :lambda 形参列表 :参数类型可以省略,如果形参列表只有一个,小括号也可以省略
->的右边:lambda体: 对应着重写方法的方法体,如果方法体中只有一条执行语句,则大括号可以省略,有return关键字,则return需要一并省略

2.方法引用

可以看做是Lambda表达式的进一步延伸

使用说明

情况1: 对象 :: 实例方法(非静态方法)
要求:函数式接口的抽象方法a与其内部实现时调用的某个方法b的形参列表和返回值类型都相同(或一致),
我们就可以考虑用方法b对方法a进行替换,此替换或覆盖称为方法引用
注:此时b是非静态的方法,需要对象来调用情况2: 类 :: 静态方法
要求:函数式接口的抽象方法a与其内部实现时调用的某个方法b的形参列表和返回值类型都相同,
我们就可以考虑用b对方法a进行替换,此替换或覆盖称为方法引用
注:此时b是静态的方法,需要类来调用情况3: 类 :: 实例方法要求:函数式接口的抽象方法a与其内部实现时时调用的对象的某个方法b的返回值类型相同
同时,抽象方法a中有n个参数,方法b中有n-1个参数,且抽象方法a的第一个参数作为方法b的调用者,且抽象方法a
的后n-1个参数与方法b的n-1个参数类型相同或一致,则可以使用方法引用注意:此方法b是静态方法,需要对象调用,但是形式上,写出a所属的类.

举例说明

1.对象::方法类型

此时我们发现get方法是空参方法,返回值是String,emp.getName()方法返回值是String形参也为空,这样就可以用这个实现的方法来覆盖原有的get方法,于是可以写作

emp::getName()

注意:这里的相同可以理解为满足多态即可.

 @Testpublic void test2(){//供给型 Supplier中的T() get//Employee 中的String getName()Employee emp = new Employee(1001,"马化腾",34,6000.38);Supplier<String> sup1 = new Supplier<String>() {@Overridepublic String get() {return emp.getName();}};System.out.println(sup1.get());//Lambda表达式写法Supplier<String> sup2 = ()-> emp.getName();System.out.println(sup2.get());//3.方法引用Supplier<String> sup3 = emp :: getName;System.out.println(sup3.get());}

2.类::静态方法举例

这里我们发现compare方法和实现中的Integer的compare方法参数和返回值一直,就可以使用方法引用,只不过这里的compare方法是静态方法,要使用类来调用,看做对原本抽象方法的一个覆盖,写作Integer :: compare;

@Testpublic void test3(){//类 :: 静态对象Comparator<Integer> com1 = new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return Integer.compare(o1,o2);}};Comparator<Integer> com2 = (o1,o2) ->Integer.compare(o1,o2);System.out.println(com2.compare(12,21));}Comparator<Integer> com3 = Integer :: compare;

3.类 :: 实例方法

这个的理解就想对困难一点点,本质和之前一样

这里我么假设抽象方法的形参有n个,实现的语句是形参1为调用者的语句

这里就可以把形参1抽象为其对应的类,剩余的返回值和形参都与原抽象方法一致

这样就可以用这种形式的方法引用代替

@Testpublic void test5(){//情况3 类 :: 实例方法(难)Comparator<String> com1 = new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {return o1.compareTo(o2);}};//2.Lambda表达式Comparator<String> com2 = (o1,o2) ->o1.compareTo(o2);//满足参数是 重写的函数的参数是需要调用的函数的参数的n+1个,也可以使用方法引用的方式Comparator<String> com3 = String :: compareTo;}

3.构造器引用/数组引用

实际上是对方法引用的一种特殊操作

就是抽象方法里面返回一个构造器,如果把构造器看做一个方法,其实本质上就一样了

 Supplier<Employee> sup1 = new Supplier<Employee>() {@Overridepublic Employee get() {return new Employee();}};Supplier<Employee> sup2 = Employee :: new;

也可以是多参数的构造器引用,因为前面的泛型参数可以直接推断你的构造器类型

public void test2(){Function<Integer,Employee> func1 = new Function<Integer, Employee>() {@Overridepublic Employee apply(Integer id) {return new Employee(id);}};System.out.println(func1.apply(12));//构造器引用Function<Integer,Employee> func2 = Employee :: new;//调用的是Employee类中参数是Integer类型的构造器func2.apply(11);}

三个,四个也是可以的

数组引用

和上面类似,不做过多解释

 Function<Integer,Employee[]> func1 = new Function<Integer, Employee[]>() {@Overridepublic Employee[] apply(Integer length) {return new Employee[length];}};Function<Integer,Employee[]> func2 = Employee[] :: new;

总结 

Lambda表达式可以对函数式接口的实现代码进行精简,(满足一定条件)进一步引出了方法引用/构造器引用/数组引用等...

秋秋语录:今日事今日毕,语法基础一定要打扎实,大处着眼,小处着手,多看多练.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/201245.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

渲染器——双端Diff算法

简单 Diff 算法利用虚拟节点的 key 属性&#xff0c;尽可能地复用 DOM 元素&#xff0c;并通过移动 DOM 的方式来完成更新&#xff0c;从而减少不断地创建和销毁DOM 元素带来的性能开销。但是&#xff0c;简单 Diff 算法仍然存在很多缺陷&#xff0c;这些缺陷可以通过双端 Diff…

Nginx部署前端项目

Nginx部署前端项目 1.在nginx官网http://nginx.org/en/download.html &#xff0c;下载稳定版本&#xff1a; 2.解压后&#xff0c;点击根目录中的nginx.exe即可启动Nginx&#xff0c;或是在nginx安装目录中启动cmd并输入以下命令启动&#xff1a; nginx.exe 或 start nginx3…

Cannot read properties of undefined (reading ‘resetFields‘)“ 报错解决

遇到这种报错 先去相关页面搜索关键字 定位到具体的报错代码 Cannot read properties of undefined (reading ‘resetFields’)" 关键字&#xff1a;resetFields 此方法作用&#xff1a;对整个表单进行重置 将所有字段值重置为初始值并移除校验结果 报错场景&#xff1a;…

SWT/Jface(1): 表格的创建和渲染

前言 使用JFace创建表格还是比较方便的, 如果仅仅是创建空表格的话, 以下2步即可完成: 创建TableViewer对象, 指定样式, 比如是否支持多行选择, 有无边框, 是否支持滚动条等创建TableColumn对象: 包括列展示名称, 宽度和样式等, 最终绑定到table对象 实例 创建表格 //注意…

深入浅出 Linux 中的 ARM IOMMU SMMU I

Linux 系统下的 SMMU 介绍 在计算机系统架构中&#xff0c;与传统的用于 CPU 访问内存的管理的 MMU 类似&#xff0c;IOMMU (Input Output Memory Management Unit) 将来自系统 I/O 设备的 DMA 请求传递到系统互连之前&#xff0c;它会先转换请求的地址&#xff0c;并对系统 I…

灵活运用Vue 3中的setup函数—深入解析Composition API

新建项目&#xff0c;项目主入口为App.vue&#xff08;主组件&#xff09;&#xff0c;新建child.vue&#xff08;子组件&#xff09;。 1.1 setup 执行 时机问题 1.在主组件里引入子组件和ref&#xff1a; import {ref} from vue import child from ./components/child.vue2…

爆款文章有诀窍,内容创作者如何能持续产出优质内容

内容营销人有没有这么一种共鸣&#xff1a;10 万 那么多&#xff0c;为什么不能多我一个&#xff1f; 通常&#xff0c;我们把浏览量 / 阅读量高、转评赞数量高的内容看作爆款&#xff0c;而数据如果达到 10 万 则是超级爆款。因为&#xff0c;阅读量高意味着内容得到了大量的曝…

Unsupervised Condition GAN

Unsupervised Condition GAN主要有两种做法&#xff1a; Direct Transformation 直接输入domain X图片&#xff0c;经过Generator后生成对应的domain Y的图像。这种转化input和output不能够差太多。通常只能实现较小的转化&#xff0c;比如改变颜色等。 Projection to Commo…

人工智能的时代---AI的影响

人工智能&#xff08;AI&#xff09;是当前科技领域的一个热门话题&#xff0c;它正在以前所未有的速度改变着我们的生活方式和工作方式。从智能家居到自动驾驶&#xff0c;从智能医疗到智能金融&#xff0c;人工智能正在渗透到我们生活的方方面面。在这篇文章中&#xff0c;我…

Java项目实战《苍穹外卖》 三、登录功能

测测你是什么人格吧&#xff0c;地址&#xff1a; MBTI 16种人格测试官网 系列文章目录 苍穹外卖是黑马程序员2023年的Java实战项目&#xff0c;作为业余练手用&#xff0c;需要源码或者课程的可以找我&#xff0c;无偿分享 Java项目实战《苍穹外卖》 一、项目概述Java项目实战…

10月起个税系统升级,3个月个税零申报将收到提示

近日&#xff0c;自然人电子税务局扣缴端升级了&#xff0c;升级后对于工资薪金收入连续三个月为零的纳税人&#xff0c;系统会自动出现以下提示。这个提示主要为了避免企业长期对已经离职的员工进行零申报&#xff0c;导致数据不准确和资源浪费。HR在申报个税时&#xff0c;一…

虚拟摇杆OnJoystickMove未被调用,角色不移动

更改interaction type 为 event notification

什么是应急演练脚本?其设计原则是什么?

应急演练脚本是一种系统性、有计划的模拟性文件&#xff0c;旨在测试和评估组织在紧急情况下的应对能力。这种脚本提供了一系列步骤和场景&#xff0c;以确保团队能够高效、协调地应对各种紧急事件。以下将详细探讨应急演练脚本的定义、设计原则以及实施过程。 一、应急演练脚本…

React整理总结(五、Redux)

1.Redux核心概念 纯函数 确定的输入&#xff0c;一定会产生确定的输出&#xff1b;函数在执行过程中&#xff0c;不能产生副作用 store 存储数据 action 更改数据 reducer 连接store和action的纯函数 将传入的state和action结合&#xff0c;生成一个新的state dispatc…

IPFoxy:什么是数据中心代理IP?好用吗?

数据中心代理是代理IP中最常见的类型&#xff0c;也被称为机房IP。这些代理服务器为用户分配不属于 ISP&#xff08;互联网服务提供商&#xff09;而来自第三方云服务提供商的 IP 地址。数据中心代理的最大优势——它们允许在访问网络时完全匿名。 如果你正在寻找海外代理IP&am…

【Java 进阶篇】揭秘 Jackson:Java 对象转 JSON 注解的魔法

嗨&#xff0c;亲爱的同学们&#xff01;欢迎来到这篇关于 Jackson JSON 解析器中 Java 对象转 JSON 注解的详细解析指南。JSON&#xff08;JavaScript Object Notation&#xff09;是一种常用于数据交换的轻量级数据格式&#xff0c;而 Jackson 作为一款优秀的 JSON 解析库&am…

js进阶笔记之原型,原型链

目录 1、原型对象 constructor 属性 对象原型 2、原型链 3、instanceof 4、原型继承 1、原型对象 面向过程就是分析出解决问题所需要的步骤&#xff0c;然后用函数把这些步骤一步一步实现&#xff0c;使用的时候再一个一个的依次调用就可以了。 面向对象是把事务分解成为…

python刷题笔记1(42例题)

1. split()函数 str.split([sep [, maxsplit]]) 分割字符串&#xff0c;返回一个数组 2. 判断子串 # 判断子串是否在主串里面&#xff0c;是则输出“Yes”&#xff0c;否则输出“No” str1 input("子串&#xff1a;") str2 input("主串:") if str1 in s…

最新绿豆APP源码苹果CMS影视插件版本/原生JAVA源码+反编译开源+免授权

源码简介&#xff1a; 最新绿豆APP源码苹果CMS影视插件版本&#xff0c;它是原生JAVA源码反编译开源免授权&#xff0c;绿豆影视对接苹果CMS&#xff0c;它可以支持多功能自定义DIY页面布局。 1、新版绿豆视频APP视频6.1插件版反编译指南及教程 2、后端插件开源&#xff0c;可…

创建 Springboot 项目

前言 创建 Spring Boot 项目是很多Java开发人员入门的重要一步&#xff01; 欢迎来到本篇关于创建 Spring Boot 项目的博客&#xff01;Spring Boot作为一个快速、便捷的开发框架&#xff0c;为我们提供了简化和加速应用程序开发的利器。 在这个数字化时代&#xff0c;快速响…