Java Lambda表达式常用的函数式接口


Posted in Java/Android onApril 07, 2022

失去人性,失去很多;失去兽性,失去一切。——《三体》

 

在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方法都会创建新的对象。

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

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

Function接口

Function接口是对实例进行处理转换的接口,定义了一个名叫apply的抽象方法,它的入参是一个泛型T对象,并返回一个泛型R对象,主要源码如下:

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

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

基本数据类型

以上介绍的几个常用的函数式接口入参和返回,都是泛型对象的,也就是必须为引用类型。当我们传入或获取的是基本数据类型时,将会发生自动装箱和自动拆箱,带来不必要的性能损耗,比如:

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();
  • 1.
  • 2.

类似这样的接口还有很多,我为大家整理了一下:

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

 

Java/Android 相关文章推荐
springBoot基于webSocket实现扫码登录
Jun 22 Java/Android
Java常用工具类汇总 附示例代码
Jun 26 Java/Android
gateway与spring-boot-starter-web冲突问题的解决
Jul 16 Java/Android
Java比较两个对象中全部属性值是否相等的方法
Aug 07 Java/Android
JAVA API 实用类 String详解
Oct 05 Java/Android
Java8中接口的新特性使用指南
Nov 01 Java/Android
JVM之方法返回地址详解
Feb 28 Java/Android
Java工作中实用的代码优化技巧分享
Apr 21 Java/Android
Springboot-cli 开发脚手架,权限认证,附demo演示
Apr 28 Java/Android
Android存储中最基本的文件存储方式
Apr 30 Java/Android
Java实现注册登录跳转
Jun 16 Java/Android
Java 中的 Lambda List 转 Map 的多种方法详解
Jul 07 Java/Android
Android Rxjava3 使用场景详解
Apr 07 #Java/Android
Java GUI编程菜单组件实例详解
Flutter集成高德地图并添加自定义Maker的实践
Apr 07 #Java/Android
详解Flutter和Dart取消Future的三种方法
Apr 07 #Java/Android
java如何实现获取客户端ip地址的示例代码
Apr 07 #Java/Android
Android Flutter实现3D动画效果示例详解
Apr 07 #Java/Android
Android Flutter实现图片滑动切换效果
You might like
PHP simplexml_import_dom()函数讲解
2019/02/03 PHP
JavaScript 核心参考教程 内置对象
2009/10/13 Javascript
jQuery 动态酷效果实现总结
2009/12/27 Javascript
NodeJS 模块开发及发布详解分享
2012/03/07 NodeJs
你必须知道的Javascript知识点之"字面量和对应类型"说明介绍
2013/04/23 Javascript
jquery 实现返回顶部功能
2014/11/17 Javascript
jQuery实现响应鼠标背景变化的动态菜单效果代码
2015/08/27 Javascript
JS实现兼容性好,自动置顶的淘宝悬浮工具栏效果
2015/09/18 Javascript
JS获取当前脚本文件的绝对路径
2016/03/02 Javascript
JS Ajax请求如何防止重复提交
2016/06/13 Javascript
可输入文字查找ajax下拉框控件 ComBox的实现方法
2016/10/25 Javascript
通过js修改input、select默认字体颜色
2017/04/19 Javascript
深入探究AngularJs之$scope对象(作用域)
2017/07/20 Javascript
jQuery与vue实现拖动验证码功能
2018/01/30 jQuery
JavaScript对象拷贝与Object.assign用法实例分析
2018/06/20 Javascript
解决vue项目nginx部署到非根目录下刷新空白的问题
2018/09/27 Javascript
vue中v-for循环给标签属性赋值的方法
2018/10/18 Javascript
微信小程序在线客服自动回复功能(基于node)
2019/07/03 Javascript
在SSM框架下用laypage和ajax实现分页和数据交互的方法
2019/09/27 Javascript
如何在vue 中引入使用jquery
2020/11/10 jQuery
跟老齐学Python之赋值,简单也不简单
2014/09/24 Python
利用Python抓取行政区划码的方法
2016/11/28 Python
Python实现的微信好友数据分析功能示例
2018/06/21 Python
python aiohttp的使用详解
2019/06/20 Python
详解Python 中sys.stdin.readline()的用法
2019/09/12 Python
Python生成验证码、计算具体日期是一年中的第几天实例代码详解
2019/10/16 Python
pycharm设置当前工作目录的操作(working directory)
2020/02/14 Python
PyQT5 实现快捷键复制表格数据的方法示例
2020/06/19 Python
HTML5实现自带进度条和滑块滑杆效果
2018/04/17 HTML / CSS
现代家居用品及礼品:LBC Modern
2018/06/24 全球购物
英国Flybe航空官网:欧洲最大的独立支线廉价航空公司
2019/07/15 全球购物
Deichmann英国:德国鞋类零售商
2021/01/30 全球购物
社团文化节邀请函
2014/01/10 职场文书
汽车服务工程专业自荐信
2014/09/02 职场文书
2014个人四风对照检查材料思想汇报
2014/09/18 职场文书
vue-treeselect的基本用法以及解决点击无法出现拉下菜单
2022/04/30 Vue.js