Lambda表达式超详解
目录
背景
Lambda表达式的用法
函数式接口
Lambda表达式的基本使用
语法精简
变量捕获
匿名内部类
匿名内部类中的变量捕获
Lambda的变量捕获
Lambda表达式在类集中的使用
Collection接口
List接口
Map接口
总结
背景
Lambda表达式是Java SE 8中的一个重要的新特性.lambda表达式允许你通过表达式来代替功能接口.lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体(body,可以是一个表达式或一个代码块).Lambda表达式基于数学中的λ演算得名,也可以称为闭包.
Lambda表达式的用法
基本语法:(parameters)->expression或(parameters)->{statements;}
Lambda表达式由三个部分组成:
1.parameters:类似方法中的形参列表,这里的参数是函数式接口里的参数.这里的参数类型可以明确声明也可不声明而由JVM隐含的判断.另外当只有一个推断类型时可以省略掉圆括号.
2.->:可理解为被用于的意思
3.方法体:可以是表达式也可以代码块,是在函数式接口里方法的实现.代码块可返回一个值或什么都不返回,这里的代码块等同于方法中的方法体,如果是表达式,可以返回一个值或者什么都不返回.
举个栗子:
//1.不需要参数,返回值为2
()->2
//2.接收一个参数(数字类型),返回其两倍的值
x -> 2 * x
//3.接收两个参数(数字),并返回它们的和
(x, y) -> x + y
//4.接收2个int型整数,返回它们的乘积
(int x, int y) -> x * y
//5.接收一个string对象,并在控制台打印,不返回任何值(看起来是返回void)
(String s) -> System.out.println(s)
函数式接口
要了解Lambda表达式,首先需要了解什么是函数式接口,函数接口定义:一个接口有且只有一个抽象方法.
注意:
1.如果一个接口有且只有一个抽象方法,那么该接口就是函数式接口
2.如果我们在某个接口上声明了@FunctionalInterface注解,那么编译器就会按照函数式接口的定义来要求该接口,这样如果有两个抽象方法,程序编译就会报错的.所以,从某种意义上来说,只要你保证你的接口中只有一个抽象方法,你可以不加这个注解.加上就会自动进行检测的.
定义方式:
@FunctionalInterface
interface NoParameterNoReturn {//注意:只能有一个方法void test();
}
但是这种方法也是可以的:
@FunctionalInterface
interface NoParameterNoReturn {void test();default void test2() {System.out.println("JDK1.8新特性,default默认方法可以有具体的实现");}
}
Lambda表达式的基本使用
首先,我们事先准备好几个接口:
//无返回值无参数
@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可以理解为:Lambda就是匿名内部类的简化,实际上是创建了一个类,实现了接口,重写了接口的方法.
没有使用lambda表达式时的调用方式:
NoParameterNoReturn noParameterNoReturn = new NoParameterNoReturn(){@Overridepublic void test() {System.out.println("hello");}
};
具体使用见以下代码:
public class TestDemo {public static void main(String[] args) {NoParameterNoReturn noParameterNoReturn = () -> {System.out.println("无参数无返回值");};noParameterNoReturn.test();OneParameterNoReturn oneParameterNoReturn = (int a) -> {System.out.println("一个参数一个返回值: " + a);};oneParameterNoReturn.test(10);MoreParameterNoReturn moreParameterNoReturn = (int a, int b) -> {System.out.println("多个参数无返回值: " + a + " " + b);};moreParameterNoReturn.test(20, 30);NoParameterReturn noParameterReturn = () -> {System.out.println("有返回值无参数! ");return 40;};//接收函数的返回值int ret = noParameterReturn.test();System.out.println(ret);OneParameterReturn oneParameterReturn = (int a) -> {System.out.println("有返回值且有一个参数");return a;};ret = oneParameterReturn.test(50);System.out.println(ret);MoreParameterReturn moreParameterReturn = (int a, int b) -> {System.out.println("有返回值且有多个参数");return a + b;};ret = moreParameterReturn.test(70, 60);System.out.println(ret);}
}
语法精简
1.参数类型可以省略,如果需要省略,每个参数的类型都需要省略.
2.参数的小括号里面只有一个参数,那么小括号可以省略.
3.如果方法体中只有一句代码,那么大括号可以省略.
4.如果方法体中只有一条语句,且是return语句,那么大括号可以省略,且去掉return关键字.
示例代码:
public static void main(String[] args) {MoreParameterNoReturn moreParameterNoReturn = (a, b) -> {System.out.println("无返回值多个参数,省略参数类型: " + a + " " + b);};moreParameterNoReturn.test(20, 30);OneParameterNoReturn oneParameterNoReturn = a -> {System.out.println("无参数一个返回值, 小括号可以省略: " + a);};oneParameterNoReturn.test(10);NoParameterNoReturn noParameterNoReturn = () -> System.out.println("无参数无返回值,方法体中只有一行代码");noParameterNoReturn.test();//方法体中只有一条语句,且是return语句NoParameterReturn noParameterReturn = () -> 40;int ret = noParameterReturn.test();System.out.println(ret);}
变量捕获
Lambda表达式中存在标量捕获,了解变量捕获之后,我们才能更好地理解Lambda表达式的作用域.
Java当中的匿名类中,会存在变量捕获.
匿名内部类
匿名内部类就是没有名字的内部类.我们这里只是为了说明变量捕获,所以,匿名内部类只要会使用即可,那么下面来简单看看匿名内部类的使用就好了.
举个简单的例子:
class Test {public void func() {System.out.println("func()");}
}public class TestDemo {public static void main(String[] args) {Test t = new Test() {@Overridepublic void func() {System.out.println("我是匿名内部类,且重写了func这个方法! ");}};t.func();}
}
在上述代码当中的main函数当中,我们看到的就是一个匿名内部类的简单使用.
匿名内部类中的变量捕获
在匿名内部类中,在使用内外的变量时,有两个条件:(要么是常量,要么是未修改的变量)
来看一下代码:
public class TestDemo1 {public static void main(String[] args) {int a = 100;Test t1 = new Test() {@Overridepublic void func() {System.out.println("我是匿名内部类,且重写了func这个方法!");System.out.println("我是捕获到变量a==" + a + "我是一个常量, 或者是一个没有改变过值的变量! ");}};t1.func();}
}
在上述代码当中变量a就是捕获的变量.这个变量要么是被final修饰,如果不是被final修饰的 你要保证在使用之前没有修改.如下代码就是错误的代码.
public class TestDemo2 {public static void main(String[] args) {int a = 100;Test t2 = new Test() {@Overridepublic void func() {a = 99;System.out.println("我是匿名内部类,且重写了func这个方法!");System.out.println("我是捕获到变量a==" + a + "我是一个常量, 或者是一个没有改变过值的变量! ");}};}
}
该代码直接编译报错.
Lambda的变量捕获
lambda其实就是可以认为是匿名内部类的实现
在lambda表达式中也可以进行变量的捕获,具体我们看一下代码.
@FunctionalInterface
interface NoParameterNoReturn {void test();
}public class TestDemo3 {public static void main(String[] args) {int a = 10;NoParameterNoReturn noParameterNoReturn = () -> {//a = 99;errorSystem.out.println("捕获变量" + a);};noParameterNoReturn.test();}
}
Lambda表达式在类集中的使用
为了能够让Lambda和java的集合类更好的一起使用,集合当中,也新增了部分接口,以便与Lambda表达式对接.
对应的接口 | 新增的方法 |
Collection | removelf() spliterator() stream() parallelStream() forEach() |
List | replaceAll() sort() |
Map | getOrDefault() forEach() replaceAll() putlfAbsent() remove() replace() computeIfAbsent() computeIfPresent() compute() merge() |
以上方法的作用可自行查看javaapi.
Collection接口
forEach()方法演示
该方法在接口Iterable当中,原型如下:
default void forEach(Consumer<? super T> action) {Objects.requireNonNull(action);for(T t : this) {action.accept(t);}
}
该方法表示:对容器中的每个元素执行action指定动作.
public class TestDemo4 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("Hello");list.add("bit");list.add("hello");list.add("lambda");list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {//简单遍历集合中元素System.out.println(s + " ");}});}
}
输出结果:
我们可以修改为如下代码:
public class TestDemo4 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("Hello");list.add("bit");list.add("hello");list.add("lambda");//表示调用一个,不带有参数的方法,其执行花括号内的语句,为原来的函数体内容.list.forEach(s -> System.out.println(s));}
}
List接口
sort()方法的演示
sort()方法源码:该方法根据c指定的比较规则对容器元素进行排序.
public void sort(Comparator<? super E> c) {final int expectedModCount = modCount;Arrays.sort((E[]) elementData, 0, size, c);if(modCount != expectedModCount) {throw new ConcurrentModificationExpection();}modCount++;
}
使用示例:
public class TestDemo5 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("hello");list.add("bit");list.add("lambda");System.out.println(list);list.sort(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {//这里比较长度return o1.length() - o2.length();}});System.out.println(list);}
}
输出结果:
修改为lambda表达式:
public class TestDemo5 {public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();list.add("hello");list.add("bit");list.add("lambda");System.out.println(list);//调用带有两个参数的方法,且返回长度的差值list.sort((str1, str2) -> str1.length() - str2.length());System.out.println(list);}
}
Map接口
HashMap的forEach()
该方法的原型如下:
default void forEach(BiConsumer<? super K, ? super V> action) {Objects.requireNonNull(action);for(Map.Entry<K, V> entry : entrySet()) {K k;V v;try {k = entry.getKey();v = entry.getValue();} catch {//this usually means the entry is no longer in the map.throw new ConcurrentModificationExpection(ise);}action.accept(k, v);}
}
作用是对Map中的每个映射执行action指定操作.
代码示例:
public class TestDemo6 {public static void main(String[] args) {HashMap<Integer, String> map = new HashMap<>();map.put(1, "hello");map.put(2, "bit");map.put(3, "hello");map.put(4, "lambda");map.forEach(new BiConsumer<Integer, String>() {@Overridepublic void accept(Integer integer, String s) {System.out.println(integer + " = " + s);}});}
}
输出结果:
使用lambda表达式之后的代码:
public class TestDemo6 {public static void main(String[] args) {HashMap<Integer, String> map = new HashMap<>();map.put(1, "hello");map.put(2, "bit");map.put(3, "hello");map.put(4, "lambda");map.forEach((k, v) -> System.out.println(k + " = " + v));}
}
总结
lambda表达式的优点很明显,在代码层次上来说,使代码变得非常地简洁.缺点也不明显,代码不易读.
优点:
1.代码简洁,开发迅速
2.方便函数式编程
3.非常容易进行并行运算
4.Java引入了Lambda,改善了集合操作
缺点:
1.代码可读性变差
2.在非并行计算中,很多计算未有传统的for性能要高
3.不容易进行调试
相关文章:

Lambda表达式超详解
目录 背景 Lambda表达式的用法 函数式接口 Lambda表达式的基本使用 语法精简 变量捕获 匿名内部类 匿名内部类中的变量捕获 Lambda的变量捕获 Lambda表达式在类集中的使用 Collection接口 List接口 Map接口 总结 背景 Lambda表达式是Java SE 8中的一个重要的新特性.…...

西门子博途与菲尼克斯无线蓝牙模块通讯
菲尼克斯无线蓝牙模块 正常运行时,可以使用基站控制字0发送00E0(得到错误代码命令) 正常运行时,可以使用基站控制字0发送00E0(得到错误代码命令)得到各个无线I/O是否连 接的信号(状态字IN word 1的第2、6、10位) 小车1连接状态 小车2连接状态 小车3连接状态 1#小车自…...

vue2 之 实现pdf电子签章
一、前情提要 1. 需求 仿照e签宝,实现pdf电子签章 > 拿到pdf链接,移动章的位置,获取章的坐标 技术 : 使用fabric pdfjs-dist vuedraggable 2. 借鉴 一位大佬的代码仓亏 : 地址 一位大佬写的文章 :地址 3. 优化 在大佬的代码…...

什么是MVC?MVC框架的优势和特点
目录 一、什么是MVC 二、MVC模式的组成部分和工作原理 1、模型(Model) 2、视图(View) 3、控制器(Controller) 三、MVC模式的工作过程如下: 用户发送请求,请求由控制器处理。 …...
主从复制mysql-replication | Replication故障排除
主从复制mysql-replication 准备环境 #防火墙 selinux systemctl stop firewalld --now &&setenforce 0 #修改主机名:hostnamectl set-hostname 名字 tip:vim /etc/sysconfig/network-scripts/ifcfg-ens33 BOOTPRTOTstatic IPADDR192.168.100.…...

基于Java SSM框架实现教学质量评价评教系统项目【项目源码+论文说明】计算机毕业设计
基于java的SSM框架实现教学质量评价评教系统演示 摘要 随着科学技术的飞速发展,社会的方方面面、各行各业都在努力与现代的先进技术接轨,通过科技手段来提高自身的优势,教学质量评价系统当然也不能排除在外。教学质量评价系统是以实际运用为…...

03|模型I/O:输入提示、调用模型、解析输出
03|模型I/O:输入提示、调用模型、解析输出 从这节课开始,我们将对 LangChain 中的六大核心组件一一进行详细的剖析。 模型,位于 LangChain 框架的最底层,它是基于语言模型构建的应用的核心元素,因为所谓 …...

springcloud-gateway-2-鉴权
目录 一、跨域安全设置 二、GlobalFilter实现全局的过滤与拦截。 三、GatewayFilter单个服务过滤器 1、原理-官方内置过滤器 2、自定义过滤器-TokenAuthGatewayFilterFactory 3、完善TokenAuthGatewayFilterFactory的功能 4、每一个服务编写一个或多个过滤器,…...

实现一个最简单的内核
更好的阅读体验,请点击 YinKai s Blog | 实现一个最简单的内核。 这篇文章带大家实现一个最简单的操作系统内核—— Hello OS。 PC 机的引导流程 我们这里将借助 Ubuntu Linux 操纵系统上的 GRUB 引导程序来引导我们的 Hello OS。 首先我们得了解一下&a…...

2024华为OD机试真题指南宝典—持续更新(JAVAPythonC++JS)【彻底搞懂算法和数据结构—算法之翼】
PC端可直接搜索关键词 快捷键:CtrlF 年份关键字、题目关键字等等 注意看本文目录-快速了解本专栏 文章目录 🐱2024年华为OD机试真题(马上更新)🐹2023年华为OD机试真题(更新中)🐶新…...

【12.23】转行小白历险记-算法02
不会算法的小白不是好小白,可恶还有什么可以难倒我这个美女的,不做花瓶第二天! 一、螺旋矩阵 59. 螺旋矩阵 II - 力扣(LeetCode) 1.核心思路:确定循环的路线,左闭右开循环,思路简…...
k8s部署nginx-ingress服务
k8s部署nginx-ingress服务 经过大佬的拷打,终于把这块的内容配置完成了。 首先去 nginx-ingress官网查看相关内容。 核心就是这个: kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/prov…...

SpringBoot Elasticsearch全文搜索
文章目录 概念全文搜索相关技术Elasticsearch概念近实时索引类型文档分片(Shard)和副本(Replica) 下载启用SpringBoot整合引入依赖创建文档类创建资源库测试文件初始化数据创建控制器 问题参考 概念 全文搜索(检索),工作原理:计算…...
Python 常用模块re
Python 常用模块re 【一】正则表达式 【1】说明 正则表达式是一种强大的文本匹配和处理工具,主要用于字符串的模式匹配、搜索和替换。正则表达式测试网址:正则表达式在线测试 正则表达式手册:正则表达式手册 【2】字符组 字符转使用[]表…...
【华为OD题库-106】全排列-java
题目 给定一个只包含大写英文字母的字符串S,要求你给出对S重新排列的所有不相同的排列数。如:S为ABA,则不同的排列有ABA、AAB、BAA三种。 解答要求 时间限制:5000ms,内存限制:100MB 输入描述 输入一个长度不超过10的字符串S,确保都是大写的。…...
Three.js 详细解析(持续更新)
1、简介; Three.js依赖一些要素,第一是scene,第二是render,第三是carmea npm install --save three import * as THREE from "three"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader.js&quo…...

Unity中Shader平移矩阵
文章目录 前言方式一:对顶点本地空间下的坐标进行相加平移1、在属性面板定义一个四维变量记录在 xyz 上平移多少。2、在常量缓冲区进行申明3、在顶点着色器中,在进行其他坐标转化之前,对模型顶点本地空间下的坐标进行转化4、我们来看看效果 方…...

python dash 的学习笔记1
dash 用python开发web界面 https://dash.plotly.com/ 官方上支持jula F# python一类。当然我只会python只学习python中使用dash. 要做一个APP,用php,java以及.net都可以写,只所有选择python是因为最近在用这一个。同时也发现python除了慢全是优点。 资料…...
SQLITE如何同时查询出第一条和最后一条两条记录
一个时间记录表,需要同时得到整个表或一段时间内第一条和最后一条两条记录,按如下方法会提示错误:ORDER BY clause should come after UNION not before select * from sdayXX order by op_date asc limit 1 union select * from sday…...

四、ensp配置ftp服务器实验
文章目录 实验内容实验拓扑操作步骤配置路由器为ftp server 实验内容 本实验模拟企业网络。PC-1为FTP 用户端设备,需要访问FTP Server,从服务器上下载或上传文件。出于安全角度考虑,为防止服务器被病毒文件感染,不允许用户端直接…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...