Function 源码解析与实践

news2025/1/15 20:35:42

作者:陈昌浩

1 导读

if…else…在代码中经常使用,听说可以通过 Java 8 的 Function 接口来消灭 if…else…!Function 接口是什么?如果通过 Function 接口接口消灭 if…else…呢?让我们一起来探索一下吧。

2 Function 接口

Function 接口就是一个有且仅有一个抽象方法,但是可以有多个非抽象方法的接口,Function 接口可以被隐式转换为 lambda 表达式。可以通过 FunctionalInterface 注解来校验 Function 接口的正确性。Java 8 允许在接口中加入具体方法。接口中的具体方法有两种,default 方法和 static 方法。

@FunctionalInterfaceinterface TestFunctionService{    void addHttp(String url);}

复制代码

那么就可以使用 Lambda 表达式来表示该接口的一个实现。

TestFunctionService testFunctionService = url -> System.out.println("http:" + url);

复制代码

2.1 FunctionalInterface

2.1.1 源码

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public @interface FunctionalInterface {}

复制代码

2.1.2 说明

上图是 FunctionalInterface 的注解说明。通过上面的注解说明,可以知道 FunctionalInterface 是一个注解,用来说明一个接口是函数式接口。 函数式接口只有一个抽象方法。 可以有默认方法,因为默认方法有一个实现,所以不是抽象的。函数接口的实例可以用 lambda 表达式、方法引用或构造函数引用创建。

FunctionalInterface 会校验接口是否满足函数式接口:

  • 类型必须是接口类型,不能是注释类型、枚举或类。

  • 只能有一个抽象方法。

  • 可以有多个默认方法和静态方法。

  • 可以显示覆盖 java.lang.Object 中的抽象方法。

编译器会将满足函数式接口定义的任何接口视为函数式接口,而不管该接口声明中是否使用 FunctionalInterface 注解。

3 Function 接口主要分类

Function 接口主要分类:

  • Function:Function 函数的表现形式为接收一个参数,并返回一个值。

  • Supplier:Supplier 的表现形式为不接受参数、只返回数据。

  • Consumer:Consumer 接收一个参数,没有返回值。

  • Runnable:Runnable 的表现形式为即没有参数也没有返回值。

3.1 Function

Function 函数的表现形式为接收一个参数,并返回一个值。

3.1.1 源码

@FunctionalInterfacepublic interface Function<T, R> {    R apply(T t);    default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {        Objects.requireNonNull(before);        return (V v) -> apply(before.apply(v));    }    default <V> Function<T, V> andThen(Function<? super R, ? extends V> after) {        Objects.requireNonNull(after);        return (T t) -> after.apply(apply(t));    }    static <T> Function<T, T> identity() {        return t -> t;    }}

复制代码

3.1.2 方法说明

  • apply:抽象方法。将此函数应用于给定的参数。参数 t 通过具体的实现返回 R。

  • compose:default 方法。返回一个复合函数,首先执行 fefore 函数应用于输入,然后将该函数应用于结果。如果任意一个函数的求值引发异常,则将其传递给组合函数的调用者。

  • andThen:default 方法。返回一个复合函数,该复合函数首先对其应用此函数它的输入,然后对结果应用 after 函数。如果任意一个函数的求值引发异常,则将其传递给组合函数的调用者。

  • identity:static 方法。返回一个始终返回其输入参数的函数。

3.1.3 方法举例

1)apply

测试代码:

public  String upString(String str){    Function<String, String> function1 = s -> s.toUpperCase();    return function1.apply(str);} public static void main(String[] args) {     System.out.println(upString("hello!")); }

复制代码

通过 apply 调用具体的实现。执行结果:

2)compose

测试代码:

public static void main(String[] args) {    Function<String, String> function1 = s -> s.toUpperCase();    Function<String, String> function2 = s -> "my name is "+s;    String result = function1.compose(function2).apply("zhangSan");    System.out.println(result);}

复制代码

执行结果

如结果所示:compose 先执行 function2 后执行 function1。

3)andThen

测试代码:

public static void main(String[] args) {    Function<String, String> function1 = s -> s.toUpperCase();    Function<String, String> function2 = s -> "my name is "+s;    String result = function1.andThen(function2).apply("zhangSan");    System.out.println(result);}

复制代码

执行结果:

如结果所示:

andThen 先执行 function1 后执行 function2。

  • identity

测试代码:

public static void main(String[] args) {    Stream<String> stream = Stream.of("order", "good", "lab", "warehouse");    Map<String, Integer> map = stream.collect(Collectors.toMap(Function.identity(), String::length));    System.out.println(map);}

复制代码

执行结果:

3.2 Supplier

Supplier 的表现形式为不接受参数、只返回数据。

3.2.1 源码

@FunctionalInterfacepublic interface Supplier<T> {    /**     * Gets a result.     *     * @return a result     */    T get();}

复制代码

3.2.2 方法说明

get:抽象方法。通过实现返回 T。

3.2.3 方法举例

public class SupplierTest {    SupplierTest(){        System.out.println(Math.random());        System.out.println(this.toString());    }}    public static void main(String[] args) {        Supplier<SupplierTest> sup = SupplierTest::new;        System.out.println("调用一次");        sup.get();        System.out.println("调用二次");        sup.get();}

复制代码

执行结果:

如结果所示:Supplier 建立时并没有创建新类,每次调用 get 返回的值不是同一个。

3.3 Consumer

Consumer 接收一个参数,没有返回值。

3.3.1 源码

@FunctionalInterfacepublic interface Consumer<T> {    void accept(T t);    default Consumer<T> andThen(Consumer<? super T> after) {        Objects.requireNonNull(after);        return (T t) -> { accept(t); after.accept(t); };    }}

复制代码

3.3.2 方法说明

  • accept:对给定参数 T 执行一些操作。

  • andThen:按顺序执行 Consumer -> after ,如果执行操作引发异常,该异常被传递给调用者。

3.3.3 方法举例

public static void main(String[] args) {    Consumer<String> consumer = s -> System.out.println("consumer_"+s);    Consumer<String> after = s -> System.out.println("after_"+s);    consumer.accept("isReady");    System.out.println("========================");    consumer.andThen(after).accept("is coming");}

复制代码

执行结果:

如结果所示:对同一个参数 T,通过 andThen 方法,先执行 consumer,再执行 fater。

3.4 Runnable

Runnable:Runnable 的表现形式为即没有参数也没有返回值。

3.4.1 源码

@FunctionalInterfacepublic interface Runnable {    public abstract void run();}

复制代码

3.4.2 方法说明

run:抽象方法。run 方法实现具体的内容,需要将 Runnale 放入到 Thread 中,通过 Thread 类中的 start()方法启动线程,执行 run 中的内容。

3.4.3 方法举例

public class TestRun implements Runnable {    @Override    public void run() {        System.out.println("TestRun is running!");    }}    public static void main(String[] args) {        Thread thread = new Thread(new TestRun());        thread.start();    }

复制代码

执行结果:

如结果所示:当线程实行 start 方法时,执行 Runnable 的 run 方法中的内容。

4 Function 接口用法

Function 的主要用途是可以通过 lambda 表达式实现方法的内容。

4.1 差异处理

原代码:

@Datapublic class User {    /**     * 姓名     */    private String name;    /**     * 年龄     */    private int age;    /**     * 组员     */    private List<User> parters;}    public static void main(String[] args) {        User user =new User();        if(user ==null ||user.getAge() <18 ){            throw new RuntimeException("未成年!");        }}

复制代码

执行结果:

使用 Function 接口后的代码:

@FunctionalInterfacepublic interface testFunctionInfe {    /**     * 输入异常信息     * @param message     */    void showExceptionMessage(String message);}    public static testFunctionInfe doException(boolean flag){        return (message -> {            if (flag){                throw new RuntimeException(message);            }        });    }    public static void main(String[] args) {        User user =new User();        doException(user ==null ||user.getAge() <18).showExceptionMessage("未成年!");}

复制代码

执行结果:

使用 function 接口前后都抛出了指定的异常信息。

4.2 处理 if…else…

原代码:

public static void main(String[] args) {    User user =new User();    if(user==null){        System.out.println("新增用户");    }else {        System.out.println("更新用户");    }}

复制代码

使用 Function 接口后的代码:

public static void main(String[] args) {    User user =new User();    Consumer trueConsumer = o -> {        System.out.println("新增用户");    };    Consumer falseConsumer= o -> {        System.out.println("更新用户");    };    trueOrFalseMethdo(user).showExceptionMessage(trueConsumer,falseConsumer);}public static testFunctionInfe trueOrFalseMethdo(User user){    return ((trueConsumer, falseConsumer) -> {        if(user==null){            trueConsumer.accept(user);        }else {            falseConsumer.accept(user);        }    });}@FunctionalInterfacepublic interface testFunctionInfe {    /**     * 不同分处理不同的事情     * @param trueConsumer     * @param falseConsumer     */    void showExceptionMessage(Consumer trueConsumer,Consumer falseConsumer);}

复制代码

执行结果:

4.3 处理多个 if

原代码:

public static void main(String[] args) {    String flag="";    if("A".equals(flag)){        System.out.println("我是A");    }else if ("B".equals(flag)) {        System.out.println("我是B");    }else if ("C".equals(flag)) {        System.out.println("我是C");    }else {        System.out.println("没有对应的指令");    }}

复制代码

使用 Function 接口后的代码:

public static void main(String[] args) {    String flag="B";    Map<String, Runnable> map =initFunctionMap();    trueOrFalseMethdo(map.get(flag)==null).showExceptionMessage(()->{        System.out.println("没有相应指令");    },map.get(flag));}public static   Map<String, Runnable> initFunctionMap(){    Map<String,Runnable> result  = Maps.newHashMap();    result.put("A",()->{System.out.println("我是A");});    result.put("B",()->{System.out.println("我是B");});    result.put("C",()->{System.out.println("我是C");});    return result;}public static testFunctionInfe trueOrFalseMethdo(boolean flag){    return ((runnable, falseConsumer) -> {        if(flag){            runnable.run();        }else {            falseConsumer.run();        }    });}

复制代码

执行结果:

5 总结

Function 函数式接口是 java 8 新加入的特性,可以和 lambda 表达式完美结合,是非常重要的特性,可以极大的简化代码。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

共享新机遇 共谋新发展 | 蓝海创意云携元宇宙技术参展2022昆明南博会

11月19日&#xff0c;第6届中国-南亚博览会暨第26届中国昆明进出口商品交易会&#xff08;以下简称南博会&#xff09;在昆明盛大开幕&#xff0c;经过10年的精心打造&#xff0c;南博会已经成为集国际贸易、投资洽谈、文化交流等为一体的高水平综合性国际博览会。 蓝海创意云…

草料二维码表单如何推送至工作群

在我们使用草料二维码进行隐患排查、故障报修、预约报名、巡检异常等场景时&#xff0c;需要时不时查看草料后台&#xff0c;检查是否有新的信息更新&#xff0c;或者提交后人工再单独通知一次&#xff0c;经常造成信息传递不及时&#xff0c;那么能不能当有表单提交时&#xf…

项目管理软件有哪些,哪个好用?

做过项目的朋友肯定都知道&#xff0c;项目管理软件是专门用来帮助计划和控制项目资源、成本与进度的计算机应用程序。这类软件可以帮助企业管理项目进度&#xff0c;节省项目人力成本支出&#xff0c;增进团队协作与沟通&#xff0c;提升团队成员工作效率&#xff0c;让资源可…

Java本地高性能缓存实践

Java缓存技术可分为远端缓存和本地缓存&#xff0c;远端缓存常用的方案有著名的redis和memcache&#xff0c;而本地缓存的代表技术主要有HashMap&#xff0c;Guava Cache&#xff0c;Caffeine和Encahche。远端缓存将在后面的博文中进行深入探讨&#xff0c;此处挖个坑&#xff…

【013】基于Vue的酒店客房管理系统(含管理员、普通用户两种身份(附源码数据库、课设报告)

这里写目录标题一、系统详细介绍二、系统部分设计思路三、项目获取一、系统详细介绍 前言&#xff1a; 这次带来的是基于NodejsVueMysql的酒店客房管理系统&#xff0c;含非常非常详细的课设报告&#xff0c;觉得物超所值&#xff01;文末附源码数据库、论文百度云链接 系统登…

高空简易水果采摘装置设计(CAD+proe)

目 录 摘 要 I Abstract II 1 绪论 1 1.1 选题背景及意义 1 1.2研究现状 1 1.2.1国外果园采摘机械现状 1 1.2.2国内果园采摘机械现状 4 1.2.3果园机械存在问题 5 1.2.4果园采摘机械的发展趋势 6 1.3研究主要内容 7 2 高空简易水果采摘装置原理 8 2.1 水果实采摘方式的选择 8 2.…

零基础入门JavaWeb——HTML相关知识

一、HTML概念 HTML是Hyper Text Markup Language的缩写。意思是超文本标记语言。它的作用是搭建网页结构&#xff0c;在网页上展示内容。 1.1 超文本 HTML文件本质上是文本文件&#xff0c;而普通的文本文件只能显示字符。但是HTML技术通过HTML标签把其他网页、图片、音频、…

微信公众号留言如何实时提醒

几乎每个官方品牌都有一个微信公众号&#xff0c;并且会不定期发布和品牌、产品相关的内容&#xff0c;也经常会收到一些用户的留言。但并不是运营人员每时每刻都登录在公众号后台&#xff0c;查看并回复这些用户的问题&#xff0c;如果我希望有用户给我们公众号留言后&#xf…

运动酒店,如何“奇袭”文旅产业精准蓝海赛道——缤跃酒店

近日&#xff0c;缤跃酒店战略牵手昌泰高速&#xff0c;进驻雷公坳文体产业园&#xff0c;共建江西大健康产业重点基地。作为锦江酒店(中国区)旗下360度健康运动中高端生活方式品牌&#xff0c;缤跃高调与南昌雷公坳文体产业园达成战略合作&#xff0c;强势入驻体育产业园&…

Python读取复杂电子表格(CSV)数据小技巧一则

关于CSV格式 逗号分隔值&#xff08;Comma-Separated Values&#xff0c;CSV&#xff0c;有时也称为字符分隔值&#xff0c;因为分隔字符也可以不是逗号&#xff09;&#xff0c;其文件以纯文本形式存储表格数据&#xff08;数字和文本&#xff09;。“CSV”并不是一种单一的、…

竞赛——【蓝桥杯】2022年12月第十四届蓝桥杯模拟赛第二期Java

1、最小的2022 问题描述 请找到一个大于 2022 的最小数&#xff0c;这个数转换成二进制之后&#xff0c;最低的 6 个二进制为全为 0 。 请将这个数的十进制形式作为答案提交。 答案提交 这是一道结果填空的题&#xff0c;你只需要算出结果后提交即可。本题的结果为一个整数…

VWware-安装AD域服务

AD域控就是基于轻型目录访问协议将企业网络中的资源&#xff08;包括用户、计算机、服务器、数据库、共享文件、共享打印机等&#xff09;合理、安全、有效的管理起来。通俗来说就是&#xff1a;解决了单点登录&#xff0c;简化了身份认证&#xff0c;完成了不同用户资源之间的…

Python连接Clickhouse遇坑篇,耗时一天成功连接!

首先&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;不要看网上那些乱七八糟的使用clickhouse-driver连接了&#xff0c;真tm难用&#xff0c;端口能搞死你那种&#xff0c;超级烦&#xff01; 推荐直接看官方…

建筑材料企业如何进行采购价格管理?SCM系统助力企业灵活控制采购价格

如今的“广厦千万间”早已矗立在中华大地的各个角落&#xff0c;建筑行业早已经成为中国国民经济发展的重要支柱性产业。同时随着近几年数字经济的兴起&#xff0c;给传统建筑材料行业带来了巨大挑战&#xff0c;如何优化生产运营、保障设备稳定运行、提高和稳定产品质量是每个…

string类的常用接口说明

STL六大组件&#xff1a; 容器 算法 配接器 迭代器 仿函数 空间配置器 温馨提示&#xff1a;只讲常用接口&#xff0c;使用方法说明详见代码注释 目录 一、string类对象的常见构造 二、string类对象的容量操作 三、类对象的访问及遍历操作 四、string类对象的修改操…

万古霉素修饰银纳米粒/磁性纳米微球/负载万古霉素PLGA缓释微球/硅包银纳米三角片

小编今天给大家带来的科研知识是万古霉素修饰银纳米粒/磁性纳米微球/负载万古霉素PLGA缓释微球/硅包银纳米三角片&#xff0c;来看&#xff01; 万古霉素修饰磁性纳米微球的制备: 磁性纳米粒子具有纳米粒子一般的特性外还具有超顺磁性,而且通过表面修饰可以连接上不同的生物功…

Windows10安装配置allure

1、allure官方文档&#xff1a; https://docs.qameta.io/allure/#_about 官方文档中&#xff0c;windows部署allure步骤&#xff1a; 奈何提示scoop不是內部命令 2、安装scoop scoop官方文档&#xff1a;https://scoop.sh/ 需要打开power shell&#xff0c;执行提示的两条…

【SQL Server + MySQL二 】SQL: DDL数据定义【定义、修改、删除基本表】,DML【憎删改查】,DCL数据控制语言

极其感动&#xff01;&#xff01;&#xff01;当时学数据库的时候&#xff0c;没白学&#xff01;&#xff01; 时隔很长时间回去看数据库的笔记都能看懂&#xff0c;每次都靠这份笔记巩固真的是语雀分享要花钱&#xff0c;要不一定把笔记给贴出来(;༎ຶД༎ຶ) &#xff0c;除…

SpringCloud搭建微服务之OAuth2实现SSO单点登录

SSO单点登录实现方式有多种&#xff0c;在这里不介绍理论&#xff0c;本文只讨论采用spring-security-oauth2来实现&#xff0c;本文共有三个服务&#xff0c;一个权限认证中心&#xff0c;两个客户端 1. 认证服务搭建 1.1. 引入核心依赖 <dependency><groupId>…

网络服务---OSI七层参考模型及各层工作原理详解

OSI网络模型概念 OSI模型&#xff08;Open System Interconnection/Reference Model&#xff09;是指国际标准化组织(ISO)提出的一个试图使各种计算机在世界范围内互连为网络的标准框架&#xff0c;简称OSI。1981年&#xff0c;为了解决不同体系结构的网络的互联问题&#xff…