Java中的Lambda表达式简介及应用
在接触Lambda表达式、了解其作用之前,首先来看一下,不用Lambda的时候我们是怎么来做事情的。
我们的需求是,创建一个动物(Animal)的列表,里面有动物的物种名,以及这种动物是否会跳,是否会游泳,并可以根据需要打印出会跳和会游泳的动物名。
首先我们创建一个Animal类:
public class Animal {
private String species;
private boolean canHop;
private boolean canSwim;
private boolean canFly;
public Animal(String speciesName, boolean hopper, boolean swimmer, boolean flyer) {
species = speciesName;
canHop = hopper;
canSwim = swimmer;
canFly = flyer;
}
public boolean canHop() {
return canHop;
}
public boolean canSwim() {
return canSwim;
}
public boolean canFly() {
return canFly;
}
public String toString() {
return species;
}
}
这个Animal类有四个私有的实例变量和三个共公有的方法。
变量
字符串型的species,用来记录动物的物种名,布尔型的canHop,canSwim和canFly,用来记录这种动物是否能跳,是否能游泳,是否会飞。
构造方法实例化对象的时候会给这些变量赋值。
方法
前三个是返回值为布尔型的canHop(),canSwim()和canFly(),调用方法时返回canHop,canSwim和canFly变量的值
另外还有一个重写的toString()方法,用于在程序中识别动物的物种名。
下面这段代码创建了一个ArrayList并向List内添加了五个Animal对象,对应五种动物和各自的能力:
List<Animal> animals = new ArrayList<Animal>();
animals.add(new Animal("fish", false, true, false));
animals.add(new Animal("kangroo", true, false, false));
animals.add(new Animal("rabbit", true, false, false));
animals.add(new Animal("turtle", false, true, false));
animals.add(new Animal("bird", true, true, true));
为了判断某种动物是否会跳跃或者会游泳(会不会飞先不管),我们可以写两个方法来返回Animal类的canHop()和canSwim(),即获取到了canHop和canSwim私有变量:
public boolean checkIfHopper(Animal a) {
return a.canHop();
}
public boolean checkIfSwimmer(Animal a) {
return a.canSwim();
}
在此为了说明Lambda表达式的作用,在这里我们把这两个方法分别放到两个类中,并把方法名改为test:
(不要问为什么起名叫test而不是Test或者TEST,也不要问为什么一定要把两个方法拆分到两个类里面,照做就是了,后面会说)
public class CheckIfHopper {
public boolean test(Animal a) {
return a.canHop();
}
}
public class CheckIfSwimmer {
public boolean test(Animal a) {
return a.canSwim();
}
}
(一个java文件里只能有一个public class,这里是为了方便所以把多个public class放在一段代码里的,下同)
为了校验这两种能力,我们分别创建了一个类,里面分别只有一个方法。即一个类校验一种能力。
按照这个思路,我们可以创建一个名为CheckTraits的接口,来让上面这些类来实现这个接口:
public interface CheckTraits {
boolean test(Animal a);
}
public class CheckIfHopper implements CheckTraits {
public boolean test(Animal a) {
return a.canHop();
}
}
public class CheckIfSwimmer implements CheckTraits {
public boolean test(Animal a) {
return a.canSwim();
}
}
CheckTraits接口有且只有一个方法boolean test(Animal a)。该方法接受一个Animal类型的对象,并返回布尔值。
有了校验能力的方法,接下来我们只需要去按需要调用这些方法就好了。我们来写一个print方法,接受一个动物列表animals和一个校验种类checker作为参数,打印出列表内符合要求的动物:
private static void print(List<Animal> animals, CheckTraits checker) {
for (Animal animal : animals) {
if (checker.test(animal)) {
System.out.print(animal + " ");
}
System.out.println();
}
}
完整的TraditionalSearch.java代码如下:
import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
public class TraditionalSearch {
public static void main(String[] args) {
List<Animal> animals = new ArrayList<Animal>();
animals.add(new Animal("fish", false, true, false));
animals.add(new Animal("kangroo", true, false, false));
animals.add(new Animal("rabbit", true, false, false));
animals.add(new Animal("turtle", false, true, false));
animals.add(new Animal("bird", true, true, true));
print(animals, new CheckIfHopper());
System.out.println("-----");
print(animals, new CheckIfSwimmer());
}
private static void print(List<Animal> animals, CheckTraits checker) {
for (Animal animal : animals) {
if (checker.test(animal)) {
System.out.print(animal + " ");
}
System.out.println();
}
}
}
代码输出结果为:
kangroo
rabbit
bird
-----
fish
turtle
bird
到目前为止,我们
- 创建了一个Animal类
- 写了两个校验方法,分别放到了两个类CheckIfHopper、CheckIfSwimmer里面
- 写了一个接口CheckTraits,让上面的这两个类实现自这个接口
- 在print方法里调用
print(animals, new CheckIfHopper())或print(animals, new CheckIfSwimmer())
做了这么多铺垫,所以Lambda表达式到底是什么?
首先思考一个问题,根据上面判断跳和游泳的思路,如果想增加一个是否能飞的判断,需要做什么?
- 创建一个CheckIfFlyer类
- 实现CheckTraits接口
- 设置
test()方法返回值为a.canFly(还记得这个test方法吗?这个就是我们校验能力的接口里唯一的一个方法名) - 在print方法里调用
print(animals, new CheckIfFlyer())
虽然这样做也不会增加几行代码,也就是多创建一个类的事情。但是Lambda表达式可以做到更简单:
- 在print方法里调用
print(ainmals, a -> a.canFly())或者print(ainmals, (Animal a) -> {return a.canFly();))
看到了吗?就是这样,并不需要创建一个新的类,也不需要修改test()方法。
我们来看一下Lambda表达式的结构:

- 左边的
a是Lambda表达式的唯一参数。 - 中间的箭头
->用来分隔参数和主体 - 右边的
a.canHop()是主体,调用唯一方法并返回方法的返回值
上图的结构式Lambda表达式的简洁形式,另外一种更为全面和复杂(并不):

- 当且仅当有且只有一个参数的时候,括号和参数类型才可以被省略
- 主体部分只有一条语句的时候,Lambda表达式不但可以让你省掉花括号
{ },还可以让你省略掉return和后面的分号; - 主体部分有多条语句构成一个语句块的时候,花括号内分号不可省略
现在我们了解了Lambda的形式,那么Lambda具体是怎么发挥作用的呢?这要从我们的print()方法说起:
private static void print(List<Animal> animals, CheckTraits checker)
当我们调用print(ainmals, a -> a.canFly()的时候,我们是将Lambda表达式a -> a.canFly()作为print方法的第二个参数传过去的。
print方法的第二个参数接收类型为CheckTraits的变量,所以Java会尝试将Lambda表达式映射到CheckTraits接口上:
boolean test(Animal a);
- 因为test方法接收Animal类型的变量,所以Lambda表达式的参数也必须为Animal类型
- 因为test方法的返回值是布尔型,所以Lambda主体也会返回布尔型的值
所以这里其实可以理解为,把简略形式的a -> a.canFly()映射为了具体形式的(Animal a) -> {return a.canFly();}
这里用到了一种叫延迟执行(Deferred Execution)的概念,所谓延迟执行就是”先定义,再执行“。在调用的时候定义了参数的类型和返回值,等执行到print方法里的时候再去执行主体获得返回值。
关于Lambda还有很多更复杂的应用,比如可以使用Predicate<T>接口来省掉自己写接口的步骤,感兴趣可以进一步详细学习。
参考资料:OCA: Oracle Certified Associate Java SE 8 Programmer I Study Guide
Java中的Lambda表达式简介及应用的更多相关文章
- Lambda 表达式,Java中应用Lambda 表达式
一.Lambda 表达式 简单来说,编程中提到的 lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数. 链接:知乎 先举一个普通的 Python 例 ...
- Java中的Lambda表达式
Lambda来源于希腊字母入,发音为 /'læmdə/对高数有所了解的人都知道λ用于声明一个数学逻辑系统,表示根据XX的输入参数,会返回某个Y结果.这正是编程语言中函数(方法)的意思.因此Lambd ...
- java中使用Lambda表达式的5种语法
1,标准写法 思考下述情况: String[] arr = {"program", "creek", "is", "a" ...
- Java 中的 Lambda 表达式
Lambda表达式 Lambda 表达式是 JDK1.8 的一个新特性,又称特殊的匿名内部类,可以取代大部分的匿名内部类,语法更简洁,可以写出更优雅的 Java 代码,可以极大地优化代码结构. Lam ...
- java中使用lambda表达式
使用lambda表达式能够使复杂的编写方式变的简单 lambda表达式的语法 (parameters) -> expression 或 (parameters) ->{ statement ...
- 理解和运用Java中的Lambda
前提 回想一下,JDK8是2014年发布正式版的,到现在为(2020-02-08)止已经过去了5年多.JDK8引入的两个比较强大的新特性是Lambda表达式(下文的Lambda特指JDK提供的Lamb ...
- Java中的lambda匿名函数使用
Java中的lambda匿名函数使用 lambda匿名函数的使用是为了满足某些情况下需要临时定义函数,或者事先定义,需要时才使用.在python里面,lambda表达式的表达方式为:lambda 参数 ...
- 在Android中使用Java 8的lambda表达式
作为一名Java开发者,或许你时常因为缺乏闭包而产生许多的困扰.幸运的是:Java's 8th version introduced lambda functions给我们带来了好消息;然而,这咩有什 ...
- Android中使用lambda表达式
lambda 语法简介 视频为本篇播客知识点讲解,建议采用超清模式观看, 欢迎点击订阅我的优酷 如果刚学Android,不知道怎么写点击事件可以跳转,传送门 要想在Android中使用lambda语法 ...
随机推荐
- 解决iconv函数无法转换某些中文的问题
原文: 解决iconv函数无法转换某些中文的问题 请先看以下代码,这个页面是GB2312编码的: $str = '陶喆';echo 'gb2312-'.$str;echo '<br />' ...
- 关于Tiff图片的编解码
TiffBitmapEncoder 类 (System.Windows.Media.Imaging)https://msdn.microsoft.com/zh-cn/library/ms635161( ...
- QQ邮箱打败163邮箱的过程(重视用户体验的结果)
引用 楼主 CKAOS 的回复: 目前负责一个项目,ASP.NET的,做一个网盘系统,别的都弄好了,只差一个下载文件夹的功能未实现,只能在服务器端打包成压缩文件,再发回浏览器.如何直接下载文件夹,不是 ...
- 线性回归模型(Linear Regression)及Python实现
线性回归模型(Linear Regression)及Python实现 http://www.cnblogs.com/sumai 1.模型 对于一份数据,它有两个变量,分别是Petal.Width和Se ...
- 什么是Android NDK
1.NDK是一系列工具的集合. NDK提供了一系列的工具,帮助开发者快速开发C(或C++)的动态库,并能自动将so和java应用一起打包成apk.这些工具对开发者的帮助是巨大的. NDK集成了交叉编译 ...
- java关键字-abstract
抽象:不具体,看不明白. 抽象类表象体现. 在不断抽取过程中,将共性内容中的方法声明抽取,但是方法不一样,没有抽取,这时抽取到的方法,并不具体,需要被指定关键字abstract所标示,声明为抽象方法. ...
- 高并发 Nginx+Lua OpenResty系列(10)——商品详情页
本章以京东商品详情页为例,京东商品详情页虽然仅是单个页面,但是其数据聚合源是非常多的,除了一些实时性要求比较高的如价格.库存.服务支持等通过AJAX异步加载加载之外,其他的数据都是在后端做数据聚合然后 ...
- Hexo+NexT(四):Hexo站点及Next主题配置详解
采用Hexo及NexT搭建好网站以后,有些效果不是我们需要的,Hexo及NexT提供了强大的定制功能,本文章将要讲解的就是如何在对网站进行配置及调整,达到博主需要的效果. 本文章配置环境是Hexo 3 ...
- 全自动Landsat影像温度反演软件开发
许久没有更新遥感类软件开发了,都有点生疏了,这一次我带来了一个老的算法,新的东西, 为什么这么说呢,我们知道Landat8.Landsat5等影像,单个影像去做温度反演,并没有什么太大的难度, 但是呢 ...
- spring 5.x 系列第8篇 —— 整合Redis客户端 Jedis和Redisson (代码配置方式)
文章目录 一.说明 1.1 Redis 客户端说明 1.2 Redis可视化软件 1.3 项目结构说明 1.3 依赖说明 二.spring 整合 jedis 2.1 新建基本配置文件和其映射类 2.2 ...