关于JAVA8的Lambda表达式

1. 水在前面

        这个礼拜忽然心血来潮把Lambda表达式学习了一遍,发现这玩意跟原来想象的好像不是一个东西,写个学习心得供以后复习用。还是那句话,这篇水文不能让你完全掌握,只是用来给我自己温习用的,或者也可以作为小伙伴的学习引路,别指望能读一篇文章就学会了。

2. 关于教材

        上周为了学习Lambda还特意跑去图书馆翻了好几本书(期间还被一个8、9的小屁孩鄙视了一番),最后关于Lambda表达式的学习,还是推荐这本《JAVA 8 实战》Raoul-Gabriel Urma,Mario Fusco 著 (pdf版 wx号:zhenyeli86  添加好友请说明技术交流,5毛党)。这本书从对Lambda表达式的背景、使用、以及原理都做了解释,还是我这种水货都能看懂的解释,还为继续往后面深挖扩展。

3. 学习心得

        关于Lambda的学习最大的体会是,重要的并不是Lambda本身,而是使用Lambda的上下文。这里可能有点抽象了,但是面向对象本身就是抽象的,先买个关子,好戏在后头。

3.1. Lambda语法

(parameters) -> expression
           或者
(parameters) -> {statement}

3.2. Lambda是什么

        按我的理解,Lambda本质上其实是一个函数,一个没有声明函数名称的函数,从语法上就很明显看到有参数列表和函数主体,只不过多了个“->”符号而已。  

        至于函数的返回值也是一个很有意思的事情,Lambda的函数返回值类型,是根据调用它的上下文来确定的,或者说是根据你想用它的地方的上下文确定了你对Lambada函数的返回值的定义。又有点抽象了,我们继续往后看。

3.3. Lambda用在什么地方

        敲黑板,全文浓缩成的一句话在这里了:Lambda表达式可以作为一个函数的“参数”使用,该参数的类型是一个函数式接口!

//调用fun
fun(Lambda表达式);

//其中fun的定义如下:
void fun (函数式接口 c){
    //反正这里肯会和Lambda有关
}

        神奇不?惊讶不!上文说到Lambda本质上是一个函数,就是说,一个函数的参数居然是另一个函数!对这就是Java 8的传递函数作为参数,其实我猜本质上还是值传递,只是传递了函数的地址值。

        慢着,并不是什么函数都可以把Lambda作为参数传入的,参数类型一定是“函数式接口的实例”。那什么是函数式接口呢?函数式接口就是“只有一个抽象方法的接口”。 函数式接口不能没有抽象方法,不能没有,也不能有多个,只能是一个抽象方法,至于非抽象方法,你爱整多少个就整多少个。

3.4. 稍微做个总结

        在继续水之前,我们先来做个小小的总结:Lambda 表达式本质上是一个函数,它是可以作为一个一个参数传给另一个函数使用,而这个参数的类型是函数式接口。只有一个抽象方法的接口就叫函数式接口。

3.5. Lambda怎么用

3.5.1. 挑绿苹果小程序  

        下面我们借用一个书上的例子继续水。这个例子是这样描述的,我们要写一个小功能,这个功能是在一堆苹果里面挑出绿色的苹果给用户。好的,根据这个需求,我们写一个小程序(我觉得还是要写一个可以执行的,完整的代码才方便对照阅读)。

import java.util.ArrayList;
import java.util.List;

//定义一个小苹果
class Apple{
	private	String color;
	
	public Apple(String appleColor){
		this.color = appleColor;
	}
	
	public void setColor(String appleColor) {
		this.color = appleColor;
	}
	
	public String getColor() {
		return this.color;
	}
}

举个栗子
public class Demo {
	
	//第一版的挑苹果函数
	public static List<Apple> filterApples(List<Apple> inventory){
		List<Apple> result = new ArrayList<Apple>();
		
		for (Apple apple: inventory){
			if ("green".equals(apple.getColor())) {
				result.add(apple);
			}
		}
		
		return result;
	}
    
	//主程序
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        
		List<Apple> appleList = new ArrayList<Apple>();
		appleList.add(new Apple("red"));
		appleList.add(new Apple("green"));
		appleList.add(new Apple("red"));
		
		//获取结果
		List<Apple> ret = filterApples(appleList);
		
		System.out.println("Apples: ");
		for (Apple app: ret) {
			System.out.println( app.getColor() + " apple;"); 
		}	
	
	}	

}

        上面小程序还写得不错吧,这时候业主爸爸说我除了要挑绿色的苹果,偶尔也挑红色的苹果。作为一个有经验(被折磨多次)的搬砖工,我们立马想到,爸爸下回可能还要重量大于100克的苹果、有虫子的苹果、日本苹果甚至长得像桃子的苹果。。。

 3.5.2. 使用策略模式优化

        按以前我们除了心里问候一下,肯定也会趁机卖弄下技术,整个策略模式,反正你要怎么挑我就写个对应的策略完事。看下我们写的第二版策略模式的挑苹果小功能:

import java.util.ArrayList;
import java.util.List;

//定义一个小苹果,这次增加了重量属性应付麻烦业主
class Apple{
	private	String color;
	private int weight;
	
	public Apple(String appleColor, int appleWeight){
		this.color = appleColor;
		this.weight = appleWeight;
	}
	
	public String getColor() {
		return this.color;
	}
	
	public int getWeight() {
		return this.weight;
	}
}

//苹果挑选器,函数式接口
interface AppleSelector{
	boolean test(Apple a);
}

//绿色苹果挑选器
class GreenAppleSelector implements AppleSelector{

	@Override
	public boolean test(Apple a) {
		// TODO Auto-generated method stub
		if ("green".equals(a.getColor()))
		    return true;
		else
			return false;
	}
	
}

//红色色苹果挑选器
class RedAppleSelector implements AppleSelector{

	@Override
	public boolean test(Apple a) {
		// TODO Auto-generated method stub
		if ("red".equals(a.getColor()))
		    return true;
		else
			return false;
	}
	
}

//大苹果挑选器
class BigAppleSelector implements AppleSelector{

	@Override
	public boolean test(Apple a) {
		// TODO Auto-generated method stub
		if (100 <= a.getWeight())
		    return true;
		else
			return false;
	}
	
}

public class Demo {
	
	//第一版的挑苹果函数
	public static List<Apple> filterApples(List<Apple> inventory, AppleSelector selector){
		List<Apple> result = new ArrayList<Apple>();
		
		for (Apple apple: inventory){
			if (selector.test(apple)) {
				result.add(apple);
			}
		}
		
		return result;
	}
    
	//主程序
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        
		List<Apple> appleList = new ArrayList<Apple>();
		appleList.add(new Apple("red", 100));
		appleList.add(new Apple("green", 200));
		appleList.add(new Apple("red", 50));
		
		//挑绿苹果
		AppleSelector greenSel = new GreenAppleSelector();
		List<Apple> greenRet = filterApples(appleList, greenSel);
		
		//挑大苹果
		AppleSelector bigSel = new BigAppleSelector();
	    List<Apple> bigRet = filterApples(appleList, greenSel);
		
		System.out.println("Green Apples: ");
		for (Apple app: greenRet) {
			System.out.println( app.getColor() + " apple;"); 
		}
		
		System.out.println("Big Apples: ");
		for (Apple app: greenRet) {
			System.out.println( Integer.toString(app.getWeight()) + "g apple;"); 
		}		
		
		
	}	

}

3.5.3. Lambda版的策略模式

        写到这里小伙伴肯定要吐槽了,水了这么久连个Lambda都没见到!好了我们来看看正主怎么用。其实写道策略模式我觉得代码已经很简洁了,毕竟我只要不断的增加AppleSelector的具体实现就好了,其他的基本不用动了。但是大牛就是大牛,觉得具体实现挑选苹果策略的这段代码就的外围就出现了很多遍,不行!

因此就到了Lambda的出场时刻了!看代码:

import java.util.ArrayList;
import java.util.List;

//定义一个小苹果,这次增加了重量属性应付麻烦业主
class Apple{
	private	String color;
	private int weight;
		
	public Apple(String appleColor, int appleWeight){
		this.color = appleColor;
		this.weight = appleWeight;
	}
	
	public String getColor() {
		return this.color;
	}
	
	public int getWeight() {
		return this.weight;
	}
}

//苹果挑选器,函数式接口
interface AppleSelector{
	boolean test(Apple a);
}


public class Demo {
	
	//第一版的挑苹果函数
	public static List<Apple> filterApples(List<Apple> inventory, AppleSelector selector){
		List<Apple> result = new ArrayList<Apple>();
		
		for (Apple apple: inventory){
			if (selector.test(apple)) {
				result.add(apple);
			}
		}
		
		return result;
	}
    
	//主程序
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        
		List<Apple> appleList = new ArrayList<Apple>();
		appleList.add(new Apple("red", 100));
		appleList.add(new Apple("green", 200));
		appleList.add(new Apple("red", 50));
		
		//挑绿苹果
		List<Apple> greenRet = 
            filterApples(appleList, (Apple apple) -> "green".equals(apple.getColor()));
		
		//挑大苹果
	    List<Apple> bigRet = 
            filterApples(appleList, (Apple apple) -> 100 <= apple.getWeight());
		
		System.out.println("Green Apples: ");
		for (Apple app: greenRet) {
			System.out.println( app.getColor() + " apple;"); 
		}
		
		System.out.println("Big Apples: ");
		for (Apple app: greenRet) {
			System.out.println( Integer.toString(app.getWeight()) + "g apple;"); 
		}		
		
		
	}	

}

        原本在第二版代码中的AppleSelector接口的具体实现没了,被Lambda表达式取代了。Lambda表达式代替AppleSelector的具体实例作为参数传到了filterApples函数中。这就是Lambda的使用方法。

        这里我们需要注意一点,Lambda表达式在这个程序中的表现形式和AppleSelector的抽象函数要匹配,才不会报错

3.6. 编译器怎么识别Lambda

        水到这里,基本上讲完了Lambda表达式的使用了。我们再深挖一下,编译器是怎么工作的,专业的说法是,编译器是怎么做上下文推断的。

        让我们再次回顾一下3.3节水过的一句话:Lambda表达式可以作为一个函数的“参数”使用,该参数的类型是一个函数式接口!看看Lambda的使用:

List<Apple> bigRet = 
            filterApples(appleList, (Apple apple) -> 100 <= apple.getWeight());

        当编译器遇到了Lambda表达式,首先检查filterApples函数的参数类型,是一个AppleSelector,这是一个函数式接口,满足基本条件。再看Lambda的函数描述,参数是Apple类型,返回值是一个boolean类型,这个函数描述抽象出来就是 boolean fun(Apple a) 正好就是AppleSelector的唯一抽象方法声明。因此,编译器就是通过这样的推断,确定了Lambda表达式对应了AppleSelector的test方法。以上就是上下文推断的过程!

4. 水在最后

        呼应前文说到的,其实使用Lambda的上下文,比Lambda本身更有意思。可能我对函数式编程的内涵理解还不到位吧,我认为Lambda只是为我们提供了一种简化代码的机制,真正使代码优雅起来的是策略模式。至于说Lambda让代码变得可读性更强,我觉得见人见智吧,起码我感觉直接使用谓语似乎更容易理解。记得前东家的规范上就要求代码还是要简单易懂为优先,毕竟不知道以后是谁来读你写的代码。

        本来只是想过一遍Lambda的使用,结果书是越看越深,后面还有函数引用、函数式编程等没搞懂,还是留在下次再水吧。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

jmeter使用方法---自动化测试

HTTP信息头管理器 一个http请求会发送请求到服务器&#xff0c;请求里面包含&#xff1a;请求头、请求正文、请求体&#xff0c;请求头就是信息头Authorization头的主要用作http协议的认证。 Authorization的作用是当客户端访问受口令保护时&#xff0c;服务器端会发送401状态…

JMeter并发工具的使用

视频地址&#xff1a;Jmeter安装教程01_Jmeter之安装以及环境变量配置_哔哩哔哩_bilibili 一、JMeter是什么 JMeter是一款免安装包&#xff0c;官网下载好后直接解压缩并配置好环境变量就可以使用。 环境变量配置可参考&#xff1a;https://www.cnblogs.com/liulinghua90/p/…

阿里云效流水线—发布公用jar到Maven私仓

后端项目发布 1.选择流水线 2.新建流水线 3.选择模板 4.选择代码仓库 5.调整构建命令 添加mvn install 重新构建项目 6.添加镜像 在wms-app目录下新建Dockerfile文件(Dockerfile文件名中的D一定要是大写的&#xff09;文件&#xff0c;重新推送项目 #基础镜像 FROM openjd…

windows libcurl异常排查 杀毒与防火墙拦截

今天遇到一个机器&#xff0c; libcurl库访问报错&#xff0c;6 解析主机异常 后来下载了一个curl客户端放到机器上&#xff0c;访问报 curl getaddrinfo thread failed to start查找一些资料&#xff0c;说是杀毒软件对网络做了限制 后来通过允许程序通过网络防火墙解决此问…

C# WPF编程-控件

C# WPF编程-控件 概述WPF控件类别包括以下控件&#xff1a;背景画刷和前景画刷字体文本装饰和排版字体继承字体替换字体嵌入文本格式化模式鼠标光标 内容控件Label&#xff08;标签&#xff09;Button&#xff08;按钮&#xff09; 概述 在WPF领域&#xff0c;控件通常被描述为…

HTML5和CSS3笔记

一&#xff1a;网页结构(html)&#xff1a; 1.1&#xff1a;页面结构&#xff1a; 1.2&#xff1a;标签类型&#xff1a; 1.2.1&#xff1a;块标签&#xff1a; 1.2.2&#xff1a;行内标签&#xff1a; 1.2.3&#xff1a;行内块标签&#xff1a; 1.2.4&#xff1a;块标签与行…

CI/CI实战-jenkis结合gitlab 4

实时触发 安装gitlab插件 配置项目触发器 生成令牌并保存 配置gitlab 测试推送 gitlab的实时触发 添加jenkins节点 在jenkins节点上安装docker-ce 新建节点server3 安装git和jdx 在jenkins配置管理中添加节点并配置从节点 关闭master节点的构建任务数

MySQL 8.0-索引- 不可见索引(invisible indexes)

概述 MySQL 8.0引入了不可见索引(invisible index)&#xff0c;这个在实际工作用还是用的到的&#xff0c;我觉得可以了解下。 在介绍不可见索引之前&#xff0c;我先来看下invisible index是个什么或者定义。 我们依然使用拆开来看&#xff0c;然后再把拆出来的词放到MySQL…

红桃写作方便吗 #学习方法#微信#微信

红桃写作是一个非常好用的论文写作工具&#xff0c;它不仅方便快捷&#xff0c;而且非常靠谱&#xff0c;能够帮助用户轻松完成论文写作任务。不论是学生还是专业人士&#xff0c;都可以通过红桃写作轻松地完成论文的写作工作&#xff0c;大大提高工作效率。 首先&#xff0c;红…

对话悠易科技蔡芳:品牌逐渐回归核心能力建设,布局和构建自己的流量阵地

关于SaaS模式在中国的发展&#xff0c;网上出现多种声音。Marteker近期采访了一些行业专家&#xff0c;围绕SaaS模式以及Martech在中国的发展提出独特观点。悠易科技副总裁蔡芳认为&#xff0c;中国目前存在SaaS的应用场景与客户需求&#xff0c;用户的应用能力也在提升&#x…

工作中常用到的Linux命令

系统&#xff0c;用户信息操作相关命令 查看主机ip地址 ifconfig 获取用户信息 id 修改用户密码 passwd 查看链接用户 who 创建新用户账号 useradd 删除用户账号 userdel 修改用户账号的属性 usermod 查看系统发行版本 cat /proc/version 说明适用于所有版本。…

鸿蒙Harmony应用开发—ArkTS-ForEach:循环渲染

ForEach基于数组类型数据执行循环渲染。 说明&#xff1a; 从API version 9开始&#xff0c;该接口支持在ArkTS卡片中使用。 接口描述 ForEach(arr: Array,itemGenerator: (item: Array, index?: number) > void,keyGenerator?: (item: Array, index?: number): string …

【算法每日一练]-图论(保姆级教程篇16 树的重心 树的直径)#树的直径 #会议 #医院设置

目录 树的直径 题目&#xff1a;树的直径 &#xff08;两种解法&#xff09; 做法一&#xff1a; 做法二&#xff1a; 树的重心&#xff1a; 题目&#xff1a; 会议 思路&#xff1a; 题目&#xff1a;医院设置 思路&#xff1a; 树的直径 定义&#xff1a;树中距离最…

excel统计分析——秩相关分析

参考资料&#xff1a;生物统计学&#xff0c;https://real-statistics.com/statistics-tables/spearmans-rho-table/ 相关于回归分析法只适用于正态分布资料&#xff0c;对于非正态分布资料&#xff0c;需要使用新的分析方法。秩相关分析也称为等级相关分析&#xff0c;是分析成…

Linux——生产者消费者模型

为何要使用生产者消费者模型 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯&#xff0c;而通过阻塞队列来进行通讯&#xff0c;所以生产者生产完数据之后不用等待消费者处理&#xff0c;直接扔给阻塞队列&#xff0c;…

硬核分享|使用AI模型给黑白照片上色与高清修复

硬核分享|使用AI模型给黑白照片上色与高清修复_哔哩哔哩_bilibili 本文介绍了如何修复褪色、模糊或损坏的图片以及老旧照片上色的工具及使用方法&#xff1b; 低清修复前 高清修复后 我们在日常生活中可能会频繁地接触到一些历史悠久、画面模糊甚至破损严重的照片。这类照片往往…

使用Intellij idea编写Spark应用程序(Scala+Maven)

使用Intellij idea编写Spark应用程序(ScalaMaven) 对Scala代码进行打包编译时&#xff0c;可以采用Maven&#xff0c;也可以采用sbt&#xff0c;相对而言&#xff0c;业界更多使用sbt。这里介绍IntelliJ IDEA和Maven的组合使用方法。IntelliJ IDEA和SBT的组合使用方法&#xf…

如何使用OpenHarmony实现一个模拟应用首次启动

应用首次启动&#xff08;ArkTS&#xff09; 介绍 本篇Codelab基于自定义弹框、首选项和页面路由实现一个模拟应用首次启动的案例。需要完成以下功能&#xff1a; 实现四个页面&#xff0c;启动页、隐私协议页、广告页、应用首页。页面之间的跳转。实现自定义隐私协议弹窗&a…

JAVA实战开源项目:大病保险管理系统(Vue+SpringBoot)

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 系统配置维护2.2 系统参保管理2.3 大病保险管理2.4 大病登记管理2.5 保险审核管理 三、系统详细设计3.1 系统整体配置功能设计3.2 大病人员模块设计3.3 大病保险模块设计3.4 大病登记模块设计3.5 保险审核模块设计 四、…

C程序编译、链接与项目构建

C程序编译、链接与项目构建 摘要C编译环境静、动态库介绍gcc与g和程序编译、链接Visual Studio创建和链接库动态库的显示调用 Make介绍安装使用 CMake介绍安装使用构建方式内部构建外部构建构建使用静/动态库常用[系统]变量常用指令CMake模块 Make与CMake的联系与区别 摘要 本…