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.hqwc.cn/news/206813.html

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

相关文章

解决ESP32内部RAM内存不足的问题

一&#xff0c;为什么需要外部RAM ESP32有520kB的内部RAM空间可以使用&#xff0c;这对于一般的情况是够用的&#xff0c;但是如果设备需要涉及音频或者显示图像等处理时&#xff0c;需要更大的内存空间来处理这些数据。ESP32支持扩展外部RAM&#xff0c;其实乐鑫已经在其ESP32…

Axios简单使用与配置安装-Vue

安装Axios npm i axios main.js 导入 import Axios from axios Vue.prototype.$axios Axios简单发送请求 get getTest() {this.$axios({method: GET,url: https://apis.jxcxin.cn/api/title?urlhttps://apis.jxcxin.cn/}).then(res > {//请求成功回调console.log(res)}…

【LeetCode刷题】-- 29.两数相除

29.两数相除 思路&#xff1a; class Solution {public int divide(int dividend, int divisor) {//考察被除数为最小值的情况if(dividend Integer.MIN_VALUE){//被除数为最小值&#xff0c;除数是1&#xff0c;返回最小值if(divisor 1){return Integer.MIN_VALUE;}//除数是-…

重磅!这本30w人都在看的Python数据分析畅销书:更新了!

想学习python进行数据分析&#xff0c;这本《利用python进行数据分析》是绕不开的一本书。目前该书根据Python3.10已经更新到第三版。 Python 语言极具吸引力。自从 1991 年诞生以来&#xff0c;Python 如今已经成为最受欢迎的解释型编程语言。 pandas 诞生于2008年。它是由韦…

2024贵州大学计算机考研分析

24计算机考研|上岸指南 贵州大学 贵州大学计算机科学与技术学院&#xff08;贵州大学省级示范性软件学院&#xff09;位于贵州省贵阳市花溪区贵州大学东校区。 计算机科学与技术学院&#xff08;软件学院&#xff09;自1972年创办计算机软件本科专业开始&#xff0c;至今已有…

Python安装入门

目录 1 从应用商店安装2 通过官方安装3 验证安装是否成功4 打印hello world总结 1 从应用商店安装 推荐使用微软的应用商店安装&#xff0c;打开开始菜单 在应用商店搜索python 选择最新的版本下载并安装即可 2 通过官方安装 也可以使用官网的安装包&#xff0c;输入如下网…

csdn最新最全pytest系列——pluggy插件源码解读(一)HookspecMarker类和HookimplMarker类分析

简介 pluggy是一个非常优秀的插件系统&#xff0c;它是理解pytest的核心&#xff0c;只有理解了pluggy的原理&#xff0c;才能更好的理解和使用pytest&#xff0c;否则见到了pytest的很多应用都会感觉很难理解 pluggy插件总共的代码量不足一千行&#xff0c;而实现的功能却是…

RTS 客户端-服务器网络

Stone Monarch 从一开始就支持多人游戏&#xff0c;但随着时间的推移&#xff0c;网络模型经历了多次迭代。我最初基于这篇著名的帝国时代文章实现了点对点锁步模型。 点对点锁定步骤有一些众所周知的问题。点对点方面使玩家很难相互连接&#xff0c;并增加了每个新玩家的网络…

vivado产生报告阅读分析15-时序报告11

Report Clock Domain Crossings “ Clock Domain Crossings (CDC) ” &#xff08; 时钟域交汇 &#xff09; 报告可对设计中的时钟域交汇执行结构分析。此信息可用于识别潜在不安全的 CDC &#xff0c; 此类 CDC 可能导致亚稳态或数据一致性问题。虽然 CDC 报告与“ Clock …

PostMan接口测试教程

1、下载和安装 Postman: 前往 Postman 官网 &#xff08;https://www.postman.com&#xff09;&#xff0c;下载适用于你的操作系统的 Postman 客户端。 执行下载后的安装程序&#xff0c;并按照安装向导的指引完成安装过程。 2、创建一个新的集合&#xff1a; 打开 Postma…

Python配置与测试利器:Hydra + pytest的完美结合

简介&#xff1a;Hydra 和 pytest 可以一起使用&#xff0c;基于 Hydra Pytest 的应用可以轻松地管理复杂配置&#xff0c;并编写参数化的单元测试&#xff0c;使得Python开发和测试将变得更为高效。 安装&#xff1a; pip install hydra-core pytest案例源码&#xff1a;my…

LabVIEW如何获取波形图上游标所在位置的数值

LabVIEW如何获取波形图上游标所在位置的数值 获取游标所在位置数值的一种方法是利用波形图的游标列表属性。 在VI的程序框图中&#xff0c;右键单击波形图并选择创建引用 &#xff0c;然后将创建的引用节点放在程序框图上。 在程序框图上放置一个属性节点&#xff0c;并将其…