【javaSE-语法】lambda表达式

【javaSE-语法】lambda表达式

  • 1. 先回忆一下:
    • 1.1 接口不能直接通过关键字new进行实例化
    • 1.2 函数式接口
    • 1.3 匿名内部类
      • 1.31 匿名内部类在代码中长啥样?
      • 1.32 构造一个新的对象与构造一个扩展了某类的匿名内部类的对象,两者有什么区别?
      • 1.33 如何调用匿名内部类对象中的成员
      • 1.34 匿名内部类的变量捕获
  • 2. lambda表达式
    • 2.1 语法
    • 2.2 基本使用
    • 2.3 lambda的变量捕获
    • 2.4 lambda在集合中的使用
      • 2.41 Collection接口下的forEach()方法和lambda的梦幻联动
      • 2.42 List接口下的sort()方法和lambda的梦幻联动
  • 4. lambda表达式的优缺点

1. 先回忆一下:

1.1 接口不能直接通过关键字new进行实例化

  1. 接口是引用数据类型,代码中使用interface定义一个接口。接口中的成员变量默认被public static final修饰,接口中的成员方法默认被public abstract修饰,抽象方法没有具体的实现。

  2. 接口中成员方法如果用defaul或者static修饰,该成员方法可以有具体的实现。

    • 接口不能通过new关键字进行实例化:在这里插入图片描述

    • 类通过关键字implement实现接口,类实现接口后,要重写接口中的所有抽象方法。通过实例化(实现了某接口的)类,间接实例化某接口在这里插入图片描述

  3. 接口间可以通过关键字extends进行拓展,即把多个接口合并在一起。在这里插入图片描述

1.2 函数式接口

如果一个接口中有且只有一个抽象方法,那么该接口就是一个函数式接口。在这里插入图片描述

  1. 在写代码时,如果在某个接口上声明了@FunctionalInterface,表示该接口必须是一个函数式接口,否则程序编译会报错。
  2. 下面这种也是函数式接口:
    在这里插入图片描述

1.3 匿名内部类

1.31 匿名内部类在代码中长啥样?

如果一个类定义在类的内部或者方法的内部,该类就是内部类。根据内部类在代码中的位置,内部类可以分为成员内部类和局部内部类。成员内部类与外部类成员所处位置相同,局部内部类定义在方法内部。在这里插入图片描述
匿名内部类和局部内部类一样,都在方法内部,且匿名内部类必须实现接口或者继承其他类。

我们在写代码的时候,如果想在方法内部创建一个类,但是不会用到该类的名字,此时就可以使用匿名内部类。如上述代码中的两个匿名内部类:

  • 第一个匿名内部类的意思是:有一个没有名字的类,该类实现了A接口,并且重写了A接口中的testA方法。在这里插入图片描述

  • 如果用局部内部类实现,代码如下:在这里插入图片描述

  • 第二个匿名内部类的意思是:有一个没有名字的类,该类继承了类B,但没有进行扩展。(一般都要进行扩展,即添加新的成员,否则该匿名内部类无意义)。在这里插入图片描述

  • 如果用局部内部类实现,代码如下:在这里插入图片描述

1.32 构造一个新的对象与构造一个扩展了某类的匿名内部类的对象,两者有什么区别?

如果构造参数列表的,结束小括号后面跟一个开始大括号,就是在定义匿名内部类对象。在这里插入图片描述

1.33 如何调用匿名内部类对象中的成员

在这里插入图片描述

1.34 匿名内部类的变量捕获

在匿名内部类中,不仅能访问外部类的字段,还能访问局部变量。但是无论是字段还是局部变量,都只能是一旦赋值绝不会改变的变量或者被final修饰的常量。

2. lambda表达式

lambda表达式是匿名内部类的简化。说的再详细一点,lambda表达式创建了一个类,实现了一个接口,重写了接口的方法

看下面代码,在代码中对象priorityQueue和对象priorityQueue1完全一样,但是显然,创建priorityQueue1的代码要更加简洁。这是因为创建priorityQueue的时候,构造方法的参数是一个匿名内部类,而创建priorityQueue1的时候,构造方法的参数一个lambda表达式。
所以,使用lambda表达式能让能让代码更加简洁,开发也随之更加迅速,这就是我们学习lambda表达式的原因。
在这里插入图片描述

2.1 语法

lambda表达式的语法: (parameters) -> expression 或 (parameters) ->{ statements; }

  1. parameters是参数,根据实际情况,参数可以有,也可以没有。这里的参数等同于方法的参数列表。
    • 参数的数据类型可以明确声明,也可以不声明而是让JVM推断。如果要省略,每个参数的数据类型都要省略。
    • 当只有一个没有声明类型的参数时,可以省略外面的小括号()。
  2. expression是表达式,是函数式接口里方法的实现。
  3. statements;是代码块,是函数式接口里方法的实现。这里的代码块和表达式等同于方法里面的方法体。
    • 如果方法体中只有一条代码,大括号{}可以省略
    • 如果方法体中只有一条语句,且是return语句,大括号和关键字return可同时省略。

例如:

// 1. 不需要参数,返回值为 2
() -> 2
// 2. 接收一个参数(数字类型),返回其2倍的值
x -> 2 * x
// 3. 接受2个参数(数字),并返回他们的和
(x, y) -> x + y
// 4. 接收2个int型整数,返回他们的乘积
(int x, int y) -> x * y
// 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void)
(String s) -> System.out.print(s)

2.2 基本使用

接下来跟着具体场景看看lambda表达式在代码中究竟如何使用:

  1. 已知函数式接口NoParameterNoReturn,接口中的test()方法没有参数,没有返回值。如何调用接口中的test()方法呢?在这里插入图片描述运行结果:
    在这里插入图片描述
  2. 下面是使用lambda表达式的更多例子:
public class Test {public static void main1(String[] args) {//如何调用接口NoParameterNoReturn中的test方法?//不使用lambda表达式(通过匿名内部类实现接口,重写方法):NoParameterNoReturn noParameterNoReturn =new NoParameterNoReturn() {@Overridepublic void test() {System.out.println("test......");}};noParameterNoReturn.test();//使用lambda表达式NoParameterNoReturn noParameterNoReturn1 =()-> System.out.println("test......");//重写接口中的方法,该方法没有参数,没有返回值noParameterNoReturn1.test();}public static void main2(String[] args) {//如何调用接口OneParameterNoReturn中的test方法?OneParameterNoReturn oneParameterNoReturn = (x)->{System.out.println(x);};//只有一个没声明类型的参数,小括号()可以省略;方法体中只有一条语句,{}可以省略oneParameterNoReturn.test(10);//如何调用接口MoreParameterNoReturn中的test()方法?test()方法无返回值但是有多个参数MoreParameterNoReturn moreParameterNoReturn =(int x,int y) -> {System.out.println(x+y);};moreParameterNoReturn.test(10,20);}public static void main(String[] args) {//如何调用接口NoParameterReturn中的test方法?test方法中有返回值,无参数NoParameterReturn noParameterReturn =() -> {return 10;};//return和{}可同时省略System.out.println(noParameterReturn.test());//如何调用接口OneParameterReturn中的test方法?test方法中有返回值,有一个参数OneParameterReturn oneParameterReturn = x -> x;oneParameterReturn.test(20);//传20返回20//如何调用接口MoreParameterReturn中的test方法?test方法中有返回值,有多个参数MoreParameterReturn moreParameterReturn =(a,b) -> {return a*b;};moreParameterReturn.test(10,20);//返回200}
}
//无返回值无参数
@FunctionalInterface
interface NoParameterNoReturn {void test();
}
//无返回值一个参数
@FunctionalInterface
interface OneParameterNoReturn {void test(int a);
}
//无返回值多个参数
@FunctionalInterface
interface MoreParameterNoReturn {void test(int a,int b);
}
//有返回值无参数
@FunctionalInterface
interface NoParameterReturn {int test();
}
//有返回值一个参数
@FunctionalInterface
interface OneParameterReturn {int test(int a);
}
//有返回值多参数
@FunctionalInterface
interface MoreParameterReturn {int test(int a,int b);
}

所以如果想在代码中使用lambda表达式,一定要清楚函数式接口中要被重写的方法,该方法中是否有返回值,是否有参数

2.3 lambda的变量捕获

同匿名内部类的变量捕获一样,lambda表达式内不仅能访问外部类的字段,还能访问局部变量。但是无论是字段还是局部变量,都只能是一旦赋值绝不会改变的变量或者被final修饰的常量。

例如在下面代码中:
在这里插入图片描述在多线程编程中,经常会用到lambda表达式,尤其要注意变量捕获这一点,如果在lambda表达式这种用了某变量,但在后续又修改了该变量,代码就会出现问题。

2.4 lambda在集合中的使用

lambda表达式是JavaSE8中的一个重要的新特性。为了能让Lambda和Java的集合类集更好的一起使用,集合当中,也新增了部分接口,以便与Lambda表达式对
接。

对应的接口新增的方法
CollectionremoveIf() spliterator() stream() parallelStream() forEach()
ListreplaceAll() sort()
MapgetOrDefault() forEach() replaceAll() putIfAbsent() remove() replace() computeIfAbsent() computeIfPresent() compute() merge()

接下来会分别演示在Collection接口forEach() 方法中,在List接口sort()方法中,分别如何使用lambda表达式。

其他方法在遇到时,查看Java帮助手册或查看对应源码,同样的方法学习掌握即可。

2.41 Collection接口下的forEach()方法和lambda的梦幻联动

  1. 先找到Collection接口下forEach()方法中的函数式接口:

Collection接口拓展了Iterable接口,在这里插入图片描述

forEach()方法在Iterable接口中,
在这里插入图片描述
forEach()方法的源码如下:从源码中看出,forEach()方法的功能就是遍历当前集合中的元素,然后让每个元素执行action.accept()操作
在这里插入图片描述
forEach()方法的参数action的类型是一个函数式接口,其中的void accept(T t)抽象函数,有一个参数无返回值。
在这里插入图片描述所以当我们调用forEach()方法的时候,forEach()方法的参数是一个函数式接口action,我们需要实现该接口并且重写接口中的accept()的方法。此时我们可以使用匿名内部类或者lambda表达式:

  1. 例如下列代码:

在这里插入图片描述

2.42 List接口下的sort()方法和lambda的梦幻联动

  1. 先找到List接口下sort()方法中涉及的函数式接口:

sort()方法的源码如下:
从源码中看出,sort()方法的功能就是先调用Arrays工具包中的sort方法,并依据比较器c的规则对当前容器元素进行排序。然后再对已经排好序的当前容器进行迭代操作。
在这里插入图片描述
sort方法的参数c的类型是一个函数式接口,其中的int compare(T o1, T o2)抽象函数,有两个参数有返回值。
函数式接口Comparator所以当我们调用sort()方法的时候,sort()方法的参数是一个函数式接口c,我们需要实现该接口并且重写接口中的compare()的方法。此时我们可以使用匿名内部类或者lambda表达式:

2.例如下面代码:
在这里插入图片描述

4. lambda表达式的优缺点

Lambda表达式的优点很明显,在代码层次上来说,使代码变得非常的简洁。缺点也很明显,代码不易读。

优点:

  1. 代码简洁,开发迅速
  2. 方便函数式编程
  3. 非常容易进行并行计算
  4. Java 引入 Lambda,改善了集合操作

缺点:

  1. 代码可读性变差
  2. 在非并行计算中,很多计算未必有传统的 for 性能要高
  3. 不容易进行调试


好了,本篇到这就结束了,相信读完本篇的你已经能读懂,会用lambda表达式了。最后祝你我早日成为技术流。

我是一朵忽明忽暗的云,点赞收藏加关注,我们一起进步!
在这里插入图片描述

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

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

相关文章

midjourney提示词语法

更高级的提示可以包括一个或多个图像URL、多个文本短语和一个或更多个参数 Image Prompts 可以将图像URL添加到提示中,以影响最终结果的样式和内容。图像URL总是位于提示的前面。 https://docs.midjourney.com/image-prompts Text Prompt 要生成的图像的文本描述。…

YOLOv6、YOLOv7、YOLOv8网络结构图(清晰版)

承接上一篇博客:YOLOv3、YOLOv4、YOLOv5、YOLOx的网络结构图(清晰版)_yolox网络结构图-CSDN博客 1. YOLOv6网络结构图 2. YOLOv7网络结构图 3. YOLOv8网络结构图

搭建 LNMP 架构

一 理论知识 (一)架构图 (二)CGI 由来 最早的Web服务器只能简单她响应浏览器发来的HTTP请求,并将存储在服务器上的HTML文件返回给浏览器,也就是静态html文件,但是后期随着网站功能增多网站开…

c++阶梯之模板初阶

1. 泛型编程 void Swap(int& x, int& y) {int tmp x;x y;y tmp; }void Swap(double& x, double& y) {double tmp x;x y;y tmp; }void Swap(char& x, char& y) {char tmp x;x y;y tmp; } int main() {int a 10, b 20;double c 1.1, d 2.2…

《Spring Security 简易速速上手小册》第7章 REST API 与微服务安全(2024 最新版)

文章目录 7.1 保护 REST API7.1.1 基础知识详解7.1.2 重点案例:使用 JWT 进行身份验证和授权案例 Demo 7.1.3 拓展案例 1:API 密钥认证案例 Demo测试API密钥认证 7.1.4 拓展案例 2:使用 OAuth2 保护 API案例 Demo测试 OAuth2 保护的 API 7.2 …

linux安装matlab获取许可证

1.点击许可证 2. 3. 4. 4.主机ID 打开linux输入 /sbin/ifconfigether后边的就是 6.计算机登录名 打开linux输入 whoami7. 8. 9.

(规划)24届春招和25届暑假实习路线准备规划

春招&&暑假实习: 1.八股: 可以去一些八股网站上面进行阅读。 2.项目:至少准备1-2个项目,可以条理清晰的进行项目介绍和难点剖析。 3.算法: hot100 ,剑指offer 能刷的很熟,算法关就差…

我的相关奖项

博士录取证明 名单第53:https://yzb.bupt.edu.cn/content/content.php?p2_2_651 论文链接 第一篇:https://doi.org/10.1186/s13677-022-00373-8 第二篇:https://doi.org/10.1016/j.ipm.2022.103167 第三篇:https://doi.org/10…

Unity 脚本-生命周期常用函数

在Unity中,万物皆是由组件构成的。 右键创建C#脚本,拖动脚本到某物体的组件列表。 生命周期相关函数 using System.Collections; using System.Collections.Generic; using UnityEngine;// 必须要继承 MonoBehaviour 才是一个组件 // 类名…

matplotlib——散点图和条形图(python)

散点图 需求 我们获得北京2016年三月和十月每天白天最高气温,我们现在需要找出气温随时间变化的某种规律。 代码 # 导入库 from matplotlib import pyplot as plt import random# 解决中文乱码 import matplotlib matplotlib.rc("font",family"F…

领域驱动设计(Domain-Driven Design DDD)——战略设计1

一、概述 随着系统的增长,它会越来越复杂,当我们无法通过分析对象来理解系统的时候,就需要掌握一些操纵和理解大模型的技术了。 最负雄心的企业欲实现一个涵盖所有业务、紧密集成的系统。因大型公司的业务模型巨大且复杂,很难把它…

springboot236基于springboot在线课程管理系统的设计与实现

基于SpringBoot在线课程管理系统的设计与实现 摘要 本文首先介绍了在线课程管理系统的现状及开发背景,然后论述了系统的设计目标、系统需求、总体设计方案以及系统的详细设计和实现,最后对在线课程管理系统进行了系统检测并提出了还需要改进的问题。本系…

echarts vue 动画效果的水球图、波浪图教程

1、安装插件 前提是已经安装了echarts(我的版本是4.2.1) npm install echarts-liquidfill --save 我安装了3.1.0版本的,结果运行时报错"TypeError: wave.ensureState is not a function" 原因:echarts版本和echarts-l…

miniconda3彻底删除虚拟环境

退出虚拟环境:确保您不在要删除的虚拟环境中。如果在,使用命令 conda deactivate 来退出当前激活的虚拟环境。查看虚拟环境列表:运行命令 conda env list 或 conda info -e 来查看所有存在的虚拟环境及其路径。删除虚拟环境:使用命…

在VMware中安装CentOS 7并配置Docker

VMware安装CentOS 7 一、介绍 该文章介绍如何使用启动U盘在虚拟机里面安装系统,虚拟机版本为VMware Workstation 16 pro,Linux版本为CentOS Linux release 7.9.2009 (Core)。 二、安装 1、创建虚拟机 点击创建新的虚拟机 选择典型就可以了&#xf…

前缀和算法题(区间次方和、小蓝平衡和、大石头的搬运工、最大数组和)

一、前缀和的原理和特点 prefix表示前缀和,前缀和由一个用户输入的数组生成。对于一个数组a[](下标从1开始),我们定义一个前缀和数组prefix[],满足: prefix有一个重要的特性,可以用于快速生成p…

WordPress建站入门教程:如何安装本地WordPress网站运行环境?

有些站长想要搭建WordPress网站,又担心自己玩不转,白白浪费购买域名和主机空间的费用。像这种情况,最好的做法就是在自己电脑上安装一个WordPress网站运行环境,然后在本地电脑搭建WordPress,等熟悉掌握后再考虑购买域名…

多输入多输出 | MATLAB实现GWO-Elman灰狼优化循环神经网络多输入多输出预测

多输入多输出 | MATLAB实现GWO-Elman灰狼优化循环神经网络多输入多输出预测 目录 多输入多输出 | MATLAB实现GWO-Elman灰狼优化循环神经网络多输入多输出预测预测效果基本介绍程序设计往期精彩参考资料 预测效果 基本介绍 Matlab实现GWO-Elman灰狼优化循环神经网络多输入多输出…

如何在电脑上中恢复已删除的视频

您可以在电脑中恢复已删除的视频,无需任何繁琐的工作。您所需要做的就是阅读本文,了解恢复已删除视频的最佳方法。 一次错误的点击可能会夺走您以视频形式存储的宝贵记忆。嗯,有些视频不适合删除,您希望永远保留它们。失去这些宝…

如何使用Docker搭建StackEdit编辑器并结合内网穿透实现远程办公

文章目录 前言1. ubuntu安装VNC2. 设置vnc开机启动3. windows 安装VNC viewer连接工具4. 内网穿透4.1 安装cpolar【支持使用一键脚本命令安装】4.2 创建隧道映射4.3 测试公网远程访问 5. 配置固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址5.3 测试…