死磕Lambda表达式(四):常用的函数式接口
失去人性,失去很多;失去兽性,失去一切。——《三体》
在Java8支持Lambda表达式以后,为了满足Lambda表达式的一些典型使用场景,JDK为我们提供了大量常用的函数式接口。它们主要在 java.util.function 包中,下面简单介绍几个其中的接口及其使用示例。
Supplier接口
Supplier接口是对象实例的提供者,定义了一个名叫get的抽象方法,它没有任何入参,并返回一个泛型T对象,具体源码如下:
package java.util.function;
@FunctionalInterface
public interface Supplier<T> {
T get();
}
源码比较简单,我们来个例子。这是一个之前提过的表示口罩的类:
package one.more.study;
/**
* 口罩
*/
public class Mask {
public Mask(String brand, String type) {
this.brand = brand;
this.type = type;
}
/**
* 品牌
*/
private String brand;
/**
* 类型
*/
private String type;
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
下面我们使用Lambda表达式声明一个Supplier的实例:
Supplier<Mask> supplier = () -> new Mask("3M", "N95");
用它来创建品牌为3M、类型为N95的Mask实例:
Mask mask = supplier.get();
System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());
运行结果如下:
Brand: 3M, Type: N95
特别需要注意的是,本例中每一次调用get方法都会创建新的对象。
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
Consumer接口
Consumer接口是一个类似消费者的接口,定义了一个名叫accept的抽象方法,它的入参是一个泛型T对象,没有任何返回(void),主要源码如下:
package java.util.function;
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
结合上面的Supplier接口,我们来个例子:
Supplier<Mask> supplier = () -> new Mask("3M", "N95");
Consumer<Mask> consumer = (Mask mask) -> {
System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());
};
consumer.accept(supplier.get());
首先使用Lambda表达式声明一个Supplier的实例,它是用来创建品牌为3M、类型为N95的Mask实例;再使用Lambda表达式声明一个Consumer的实例,它是用于打印出Mask实例的相关信息;最后Consumer消费了Supplier生产的Mask。运行结果如下:
Brand: 3M, Type: N95
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
Predicate接口
Predicate接口是判断是与否的接口,定义了一个名叫test的抽象方法,它的入参是一个泛型T对象,并返回一个boolean类型,主要源码如下:
package java.util.function;
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
结合上面的Supplier接口,我们来个例子:
Supplier<Mask> supplier = () -> new Mask("3M", "N95");
Predicate<Mask> n95 = (Mask mask) -> "N95".equals(mask.getType());
Predicate<Mask> kn95 = (Mask mask) -> "KN95".equals(mask.getType());
System.out.println("是否为N95口罩:" + n95.test(supplier.get()));
System.out.println("是否为KN95口罩:" + kn95.test(supplier.get()));
首先使用Lambda表达式声明一个Supplier的实例,它是用来创建品牌为3M、类型为N95的Mask实例;再使用Lambda表达式声明一个Predicate的实例n95,它是用于判断是否为N95口罩;再使用Lambda表达式声明一个Predicate的实例kn95,它是用于判断是否为KN95口罩;最后分别用两个Predicate判断Supplier生产的Mask。运行结果如下:
是否为N95口罩:true
是否为KN95口罩:false
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
Function接口
Function接口是对实例进行处理转换的接口,定义了一个名叫apply的抽象方法,它的入参是一个泛型T对象,并返回一个泛型T对象,主要源码如下:
package java.util.function;
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
结合上面的Supplier接口,我们来个例子:
Supplier<Mask> supplier = () -> new Mask("3M", "N95");
Function<Mask, String> brand = (Mask mask) -> mask.getBrand();
Function<Mask, String> type = (Mask mask) -> mask.getType();
System.out.println("口罩品牌:" + brand.apply(supplier.get()));
System.out.println("口罩类型:" + type.apply(supplier.get()));
首先使用Lambda表达式声明一个Supplier的实例,它是用来创建品牌为3M、类型为N95的Mask实例;再使用Lambda表达式声明一个Function的实例brand,它是用于获取口罩的品牌;再使用Lambda表达式声明一个Function的实例type,它是用于获取口罩的类型;最后分别用两个Function分析Supplier生产的Mask。运行结果如下:
口罩品牌:3M
口罩类型:N95
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
BiFunction接口
Function接口的入参只有一个泛型对象,JDK还为我们提供了两个泛型对象入参的接口:BiFunction接口,主要源码如下:
package java.util.function;
@FunctionalInterface
public interface BiFunction<T, U, R> {
R apply(T t, U u);
}
我们可以用BiFunction接口传入两个String直接创建Mask实例:
BiFunction<String,String,Mask> biFunction = (String brand, String type) -> new Mask(brand, type);
Mask mask = biFunction.apply("3M", "N95");
System.out.println("Brand: " + mask.getBrand() + ", Type: " + mask.getType());
运行结果如下:
Brand: 3M, Type: N95
欢迎关注微信公众号:万猫学社,每周一分享Java技术干货。
基本数据类型
以上介绍的几个常用的函数式接口入参和返回,都是泛型对象的,也就是必须为引用类型。当我们传入或获取的是基本数据类型时,将会发生自动装箱和自动拆箱,带来不必要的性能损耗,比如:
Supplier<Long> supplier = () -> System.currentTimeMillis();
long timeMillis = supplier.get();
在上面例子里,发生了一次自动装箱(long被装箱为Long)和一次拆箱(Long被拆箱为long),如何避免这种不必要的性能损耗呢?JDK为我们提供相应的函数式接口,如LongSupplier接口,定义了一个名叫getAsLong的抽象方法,签名是() -> long。上面的例子可以优化为:
LongSupplier supplier = () -> System.currentTimeMillis();
long timeMillis = supplier.getAsLong();
类似这样的接口还有很多,我为大家整理了一下:
Supplier相关的接口
| 接口名称 | 方法名称 | 方法签名 |
|---|---|---|
| Supplier | get | () -> T |
| BooleanSupplier | getAsBoolean | () -> boolean |
| DoubleSupplier | getAsDouble | () -> double |
| IntSupplier | getAsInt | () -> int |
| LongSupplier | getAsLong | () -> long |
Consumer相关的接口
| 接口名称 | 方法名称 | 方法签名 |
|---|---|---|
| Consumer | accept | (T) -> void |
| DoubleConsumer | accept | (double) -> void |
| IntConsumer | accept | (int) -> void |
| LongConsumer | accept | (long) -> void |
| ObjDoubleConsumer | accept | (T, double) -> void |
| ObjIntConsumer | accept | (T, int) -> void |
| ObjLongConsumer | accept | (T, long) -> void |
Predicate相关的接口
| 接口名称 | 方法名称 | 方法签名 |
|---|---|---|
| Predicate | test | (T) -> boolean |
| BiPredicate | test | (T, U) -> boolean |
| DoublePredicate | test | (double) -> boolean |
| IntPredicate | test | (int) -> boolean |
| LongPredicate | test | (long) -> boolean |
Function相关的接口
| 接口名称 | 方法名称 | 方法签名 |
|---|---|---|
| Function | apply | (T) -> R |
| BiFunction | apply | (T, U) -> R |
| DoubleFunction | apply | (double) -> R |
| DoubleToIntFunction | applyAsInt | (double) -> int |
| DoubleToLongFunction | applyAsLong | (double) -> long |
| IntFunction | apply | (int) -> R |
| IntToDoubleFunction | applyAsDouble | (int) -> double |
| IntToLongFunction | applyAsLong | (int) -> long |
| LongFunction | apply | (long) -> R |
| LongToDoubleFunction | applyAsDouble | (long) -> double |
| LongToIntFunction | applyAsInt | (long) -> int |
| ToDoubleFunction | applyAsDouble | (T) -> double |
| ToDoubleBiFunction | applyAsDouble | (T, U) -> double |
| ToIntFunction | applyAsInt | (T) -> int |
| ToIntBiFunction | applyAsInt | (T, U) -> int |
| ToLongFunction | applyAsLong | (T) -> long |
| ToLongBiFunction | applyAsLong | (T, U) -> long |
《死磕Lambda表达式》系列
- 死磕Lambda表达式(一):初识Lambda
- 死磕Lambda表达式(二):Lambda的使用
- 死磕Lambda表达式(三):更简洁的Lambda
- 死磕Lambda表达式(四):常用的函数式接口
- 死磕Lambda表达式(五):Comparator复合
- 死磕Lambda表达式(六):Consumer、Predicate、Function复合
微信公众号:万猫学社
微信扫描二维码
获得更多Java技术干货

死磕Lambda表达式(四):常用的函数式接口的更多相关文章
- 死磕Lambda表达式(一):初识Lambda
弱小和无知不是生存的障碍,傲慢才是.--<三体> 什么是Lambda表达式 Lambda表达式是表示可传递匿名函数的一种简洁方式,Lambda表达式没有名称,但是有参数列表.函数主体.返回 ...
- 死磕Lambda表达式(二):Lambda的使用
城市就是森林,每一个男人都是猎手,每一个女人都是陷阱.--<三体> 在哪使用Lambda表达式? 在上一篇文章(传送门)中介绍了Lambda表达式的基本语法,其中的举了一个Lambda表达 ...
- 死磕Lambda表达式(三):更简洁的Lambda
我们都是阴沟里的虫子,但总还是得有人仰望星空.--<三体> 在之前的文章中介绍了Lambda表达式的基本语法和正确使用姿势,这次我来介绍一些Lambda更简洁的用法. 欢迎关注微信公众号: ...
- 死磕Lambda表达式(五):Comparator复合
给岁月以文明,而不是给文明以岁月.--<三体> 在上一篇文章(传送门)中介绍了JDK为我们提供的常用函数式接口,JDK不仅提供的这些函数式接口,其中一些接口还为我们提供了实用的默认方法,这 ...
- 死磕Lambda表达式(六):Consumer、Predicate、Function复合
你的无畏来源于无知.--<三体> 在上一篇文章(传送门)中介绍了Comparator复合,这次我们来介绍一下其他的复合Lambda表达式. Consumer复合 Consumer接口中,有 ...
- Lambda01 编程范式、lambda表达式与匿名内部类、函数式接口、lambda表达式的写法
1 编程范式 主要的编程范式有三种:命令式编程,声明式编程和函数式编程. 1.1 命令式编程 关注计算机执行的步骤,就是告诉计算机先做什么后做什么 1.2 声明式编程 表达程序的执行逻辑,就是告诉计算 ...
- 黑马Lambda表达式学习 Stream流 函数式接口 Lambda表达式 方法引用
- Java8新特性—四大内置函数式接口
Java8新特性--四大内置函数式接口 预备知识 背景 Lambda 的设计者们为了让现有的功能与 Lambda 表达式良好兼容,考虑了很多方法,于是产生了函数接口这个概念. 什么是函数式接口? 函数 ...
- 常用的函数式接口Function接口和常用的函数式接口Function接口默认方法andThen
常用的函数式接口Function接口 package com.yang.Test.FunctionStudy; import java.util.function.Function; /** * ja ...
随机推荐
- Dockerfile创建zabbix监控体系
使用for循环将zabbix的镜像导入到容器中 for n in `ls *.tar.gz`;do docker load -i $n ;done 使用docker运行zabbix-server do ...
- Vue错误信息解决
在运行Vue项目时提示如下错误: [Vue warn]: You are using the runtime-only build of Vue where the template compiler ...
- iOS中如何实现准确的倒计时程序 · 九十里
iOS中倒计时程序,考虑线程暂停场景. iOS App进入后台时,GCD线程也会跟着暂停.当程序进入前台后,GCD线程恢复.因而倒计时程序需要考虑这一点,通过加入时间的比对来实现. + (void)c ...
- 使用 Hexo 在 GitHub 上建立博客 · Utopia's Daily Note
使用 Hexo 在 GitHub 上建立博客 # 写在前面 其实我在一月份的就开始写了三篇博客文章,你没有看错,只是写了三篇,然后,就没有然后了.我还在其中一篇文章中写着,不知道自己能够坚持多久.事实 ...
- IT培训的背后,是“韭菜”的躺赚梦!
作者:九歌 本文转自公众号:Hack 本文只谈"骗局",不谈其他,绝不引战,如有错误,希望指出我会及时改正 导语 为什么要写这篇文章呢,近些年培训这个话题也比较火,很多在看这篇文章 ...
- Linux用户组的添加及属性的更改
用户组的创建: 12345 groupadd [OPTION] 组名 -g GID 指明GID号:[GID_MIN, GID_MAX] -r 创建系统组 CentOS 6: ID<500 Cen ...
- Grafana使用总结
最近工作需求学习了下grafana,根据创建的几个dashboard简要记录下创建过程. 本次使用了grafana做可视化展示,data source使用的rds是postgresql和时序数据库in ...
- SQLyog试用到期的解决方法(仅供个人学习使用,禁止转载或用于商业盈利)
作者:EzrealYi 本章链接:https://www.cnblogs.com/ezrealyi/p/12434105.html win+r->输入regedit->进入注册表 在计算机 ...
- 一个轻量级的基于 .NET Core 的 ORM 框架 HSQL
HSQL 是一种轻量级的基于 .NET Core 的数据库对象关系映射「ORM」框架 HSQL 是一种可以使用非常简单且高效的方式进行数据库操作的一种框架,通过简单的语法,使数据库操作不再成为难事.目 ...
- Codeforces Round #620 (Div. 2)
Codeforces Round #620 (Div. 2) A. Two Rabbits 题意 两只兔子相向而跳,一只一次跳距离a,另一只一次跳距离b,每次同时跳,问是否可能到同一位置 题解 每次跳 ...