如果还不懂如何使用 Consumer 接口,就来看这篇!

b090accdcc9246e2f34d994accb936f0.gif

作者 | 阿Q

来源 | 阿Q说代码

背景

在开发过程中我遇到这么一个问题:

表结构:一张主表A ,一张关联表B ,表 A 中存储着表 B 记录的状态。

场景:第一步创建主表数据,插入A表;第二步调用第三方接口插入B表同时更新A表的状态。此时大家应该都会想到在进行第二步的时候需要做好数据的幂等性。这样的话就会存在以下几种情况:

一、B表中不存在与A表关联的数据,此时需要调用第三方接口,插入B表同时更新A表的状态;

二、B表中存在与A表关联的数据;

  1. A表中的状态为处理中:直接返回处理中字样;

  2. A表中的状态为处理成功:直接返回成功的字样;

  3. A表中的状态为处理失败:此时需要调用第三方接口,更新B表同时更新A表的状态;

代码实现

首先我是这样编写的伪代码

B b = this.baseMapper.selectOne(queryWrapper);
if (b != null) {String status = b.getStatus();if (Objects.equals(Constants.STATUS_ING, status)){return "处理中";} else if (Objects.equals(Constants.STATUS_SUCCESS, status)){return "处理成功";}//失败的操作//请求第三方接口并解析响应结果......if (ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())) {......//更新B表操作bb.setStatus(Constants.STATUS_ING);mapper.updateById(bb);//更新A表的状态a.setStatus(Constants.STATUS_ING);aMapper.updateById(a);}} else {//请求第三方接口并解析响应结果......if (ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())) {......//插入B表操作bb.setStatus(Constants.STATUS_ING);mapper.insert(bb);//更新A表的状态a.setStatus(Constants.STATUS_ING);aMapper.updateById(a);}
}

不知道细心的小伙伴是否发现,存在B表记录并且状态为“失败”的情况和不存在B表的情况除了插入B表或者更新B表的操作之外,其余的操作都是相同的。

如果我们想要将公共的部分抽取出来,发现都比较零散,还不如不抽取,但是不抽取代码又存在大量重复的代码不符合我的风格。于是我便将手伸向了 Consumer 接口。

更改之后的伪代码

B b = this.baseMapper.selectOne(queryWrapper);
if (b != null) {String status = b.getStatus();if (Objects.equals(Constants.STATUS_ING, status)){return "处理中";} else if (Objects.equals(Constants.STATUS_SUCCESS, status)){return "处理成功";}//失败的操作getResponse(dto, response, s -> mapper.updateById(s));
} else {getResponse(dto, response, s -> mapper.updateById(s));
}public void getResponse(DTO dto, Response response, Consumer<B> consumer){//请求第三方接口并解析响应结果......if (ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())) {......bb.setStatus(Constants.STATUS_ING);consumer.accept(bb);//更新A表的状态a.setStatus(Constants.STATUS_ING);aMapper.updateById(a);}
}

看到这,如果大家都已经看懂了,那么恭喜你,说明你对 Consumer 的使用已经全部掌握了。如果你还存在一丝丝的疑虑,那么就接着往下看,我们将介绍一下四种常见的函数式接口。

a789ae44c227d4817dddc091627caab2.png

函数式接口

那什么是函数式接口呢?函数式接口是只有一个抽象方法(Object的方法除外),但是可以有多个非抽象方法的接口,它表达的是一种逻辑上的单一功能。

@FunctionalInterface

@FunctionalInterface  注解用来表示该接口是函数式接口。它有助于及早发现函数式接口中出现的或接口继承的不适当的方法声明。

如果接口用该注解来注释,但实际上不是函数式接口,则会在编译时报错。

Consumer

我们一般称之为“消费者”,它表示接受单个输入参数但不返回结果的操作。不同于其它函数式接口,Consumer 预期通过副作用进行操作。

那什么又是副作用呢?说一下我所理解的副作用,副作用其实就是一个函数是否会修改它范围之外的资源,如果有就叫有副作用,反之为没有副作用。比如修改全局变量,修改输入参数所引用的对象等。

@FunctionalInterface
public interface Consumer<T> {/***  对给定的参数执行此操作。*/void accept(T t);/*** *  返回一个组合的 Consumer ,依次执行此操作,然后执行after操作。*  如果执行任一操作会抛出异常,它将被转发到组合操作的调用者。*  如果执行此操作会引发异常,则不会执行after操作。*/default Consumer<T> andThen(Consumer<? super T> after) {Objects.requireNonNull(after);return (T t) -> { accept(t); after.accept(t); };}
}

正如我们案例中遇到的场景,我们只需要将要执行的逻辑方法当作参数传入 getResponse() 中,然后在该方法中执行 accept() 方法进行消费即可。如果还不理解,我们可以把它转换为匿名内部类的调用方式。

getResponse(dto, response, new Consumer<B>() {@Overridepublic void accept(B bb) {mapper.insert(bb);}
});

当调用accept() 方法的时候就会去调用匿名内部类的方法了,也就是我们传入 getResponse() 的逻辑方法。

Supplier

我们一般称之为“生产者”,没有参数输入,但是能返回结果,为结果的提供者。

@FunctionalInterface
public interface Supplier<T> {/***  获取一个结果*/T get();
}

可以举个简单的例子感受下:

Optional<Double> optional = Optional.empty();
optional.orElseGet(()->Math.random() );//orElseGet 方法的源码,里边用到了 get 方法
public T orElseGet(Supplier<? extends T> other) {   return value != null ? value : other.get();
}

Function

我把它称为“转换者”,表示接收一个参数通过处理之后返回一个结果的函数。

@FunctionalInterface
public interface Function<T, R> {/***  将 T 类型的参数传入,经过函数表达式的计算,返回 R 类型的结果*/R apply(T t);/*** 返回一个组合函数,先将参数应用于 before 函数,然后将结果应用于当前函数,返回最终结果。* 如果对任一函数的求值引发异常,则会将其转发给组合函数的调用方。*/default <V> Function<V, R> compose(Function<? super V, ? extends T> before) {Objects.requireNonNull(before);return (V v) -> apply(before.apply(v));}/*** 返回一个组合函数,先将参数应用与当前函数,然后将结果应用于 after 函数,返回最终的结果。* 如果对任一函数的求值引发异常,则会将其转发给组合函数的调用方。 */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;}
}

我们在 lambda 表达式中应用比较多,所以我们来简单演示下:

@Data
@AllArgsConstructor
public class Teacher {private String name;private int age;
}public class TeacherTest {public static void main(String[] args) {List<Teacher> list = Arrays.asList(new Teacher("张三",25),new Teacher("李四",28),new Teacher("王五",18));List<String> collect = list.stream().map(item -> item.getName()).collect(Collectors.toList());System.out.println(collect);}
}

其中 map 接收的参数就是 Function 类型, item 为传入参数,item.getName()  为返回处理的结果,最后输出结果为

[张三, 李四, 王五]

Predicate

我们称之为“判断者”,通过接收参数 T 来返回 boolean 的结果。

@FunctionalInterface
public interface Predicate<T> {/***  接收一个参数, 判断这个参数是否匹配某种规则, 匹配成功返回true, 匹配失败则返回false*/boolean test(T t);/***  接收一个 Predicate 类型的参数,用当前函数和 other 函数逻辑与判断参数 t 是否匹配规则,成功返回true,失败返回 false *  如果当前函数返回 false,则 other 函数不进行计算* 在评估 Predicate 期间引发的任何异常都会转发给调用方*/default Predicate<T> and(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) && other.test(t);}/***  返回当前Predicate取反操作之后的Predicate*/default Predicate<T> negate() {return (t) -> !test(t);}/***  接收一个 Predicate 类型的参数,用当前函数和 other 函数 逻辑或 判断参数 t 是否匹配规则,成功返回true,失败返回 false *  如果当前函数返回 true,则 other 函数不进行计算* 在评估 Predicate 期间引发的任何异常都会转发给调用方*/default Predicate<T> or(Predicate<? super T> other) {Objects.requireNonNull(other);return (t) -> test(t) || other.test(t);}/***  静态方法:传入一个参数,用来生成一个 Predicate,调用test() 方法时调的 object -> targetRef.equals(object) 函数式**/static <T> Predicate<T> isEqual(Object targetRef) {return (null == targetRef)? Objects::isNull: object -> targetRef.equals(object);}
}

相信大家在编码过程中经常会遇到该函数式接口,我们举个例子来说一下:

public static void main(String[] args) {List<Teacher> list = Arrays.asList(new Teacher("张三",25),new Teacher("李四",28),new Teacher("王五",18));list = list.stream().filter(item -> item.getAge()>25).collect(Collectors.toList());list.stream().forEach(item->System.out.println(item.getName()));
}

其中 filter() 的参数为 Predicate 类型的,返回结果为:李四

看到这儿,我们常见的四种函数式接口就已经介绍完了。说实话,函数式接口我已经看过好几遍了,尤其是 ConsumerSupplier。当时只是脑子里学会了,没有应用到具体的项目中,下次再遇到的时候还是一脸懵逼,不知道大家有没有这种感受。

bc18efdc7b77f4d2368eb75ba3e76375.gif

783f42d6b2fa1c574fc6907a8295cc4d.png

往期推荐

虚幻引擎5上的《黑客帝国》全新体验,爱了爱了

元宇宙真的是割韭菜吗?

Log4j 第三次发布漏洞补丁,漏洞或将长存

低代码发展专访系列之六:低代码平台能解决业务重构的问题吗?

fcbfbf08d2b5660449dada44bf279cc6.gif

点分享

f263a23a3bcf26a3597412a49ef2937b.gif

点收藏

09514d27dce870115c1e4dd8aa77a460.gif

点点赞

5fdcd2d08e4de4ad98cbde8c293167a3.gif

点在看

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

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

相关文章

京东:Flink SQL 优化实战

简介&#xff1a; 本文着重从 shuffle、join 方式的选择、对象重用、UDF 重用等方面介绍了京东在 Flink SQL 任务方面做的优化措施。 本文作者为京东算法服务部的张颖和段学浩&#xff0c;并由 Apache Hive PMC&#xff0c;阿里巴巴技术专家李锐帮忙校对。主要内容为&#xff1…

Spring Boot参数校验以及分组校验的使用

简介&#xff1a; 做web开发基本上每个接口都要对参数进行校验&#xff0c;如果参数比较少&#xff0c;还比较容易处理&#xff0c;一但参数比较多了的话代码中就会出现大量的if-else语句。虽然这种方式简单直接&#xff0c;但会大大降低开发效率和代码可读性。所以我们可以使用…

长文解析:作为容器底层技术的半壁江山, cgroup如何突破并发创建瓶颈?

简介&#xff1a; io_uring 作为一种新型高性能异步编程框架&#xff0c;代表着 Linux 内核未来的方向&#xff0c;当前仍处于快速发展中。阿里云联合 InfoQ 发起《io_uring 介绍及应用实践》的技术公开课&#xff0c;围绕 OpenAnolis 龙蜥社区 Anolis OS 8 全方位解析高性能存…

Orion:谷歌的新一代SDN控制器

作者 | 魏煌松来源 | 鲜枣课堂时至今日&#xff0c;谷歌在2015年公布的成果&#xff0c;“利用SDN将广域网带宽利用率提升至接近100%”&#xff0c;仍然是SDN的一个标杆案列&#xff0c;也是难以逾越的巅峰。但事实上&#xff0c;当时使用的SDN控制器Onix&#xff0c;早已退出了…

移动云正式发布基于龙蜥 Anolis OS 的 BC-Linux V8.2 通用版操作系统

简介&#xff1a; 2020年12月CentOS项目组宣布CentOS 8将于2021年12月31日结束支持&#xff0c;这意味着从2022年开始&#xff0c;使用CentOS 8的用户&#xff0c;将无法得到来自官方的新硬件支持、bug修复和安全补丁。针对这一情况&#xff0c;移动云大云操作系统团队基于国内…

干掉讨厌的 CPU 限流,让容器跑得更快

简介&#xff1a; 让人讨厌的 CPU 限流影响容器运行&#xff0c;有时人们不得不牺牲容器部署密度来避免 CPU 限流出现。本文介绍的 CPU Burst 技术可以帮助您既能保证容器运行服务质量&#xff0c;又不降低容器部署密度。文章分为上下两篇&#xff0c;该文为上篇&#xff0c;下…

微弱信号检测_机动车检测线常用传感器介绍

机动车检测线中经常会运用到各种传感器&#xff0c;这些传感器相当于车辆检测系统的“眼睛”、“鼻子”和“耳朵”&#xff0c;通过台体装置和装在台体中的传感器&#xff0c;能够把车辆的性能数据转换成计算机系统能够识别的信号&#xff0c;供计算机处理和计算&#xff0c;最…

赋能开发者,英特尔发布oneAPI 2022工具包

英特尔发布了oneAPI 2022工具包。此次发布的最新增强版工具包扩展了跨架构开发的特性&#xff0c;为开发者提供更强的实用性和更丰富的架构选择&#xff0c;用以加速计算。 英特尔公司首席技术官、高级副总裁、软件和先进技术事业部总经理 Greg Lavender表示&#xff1a;“我十…

Quick BI V4.0功能“炸弹”来袭,重磅推出即席分析、模板市场、企业微信免密登录等强势功能

简介&#xff1a; 2021年7月&#xff0c;Quick BI公共云版本迭代新功能&#xff1a;重磅推出即席分析、模板市场&#xff0c;分析门槛再降低&#xff1b;推出企业微信无缝对接&#xff0c;移动端类目个性配置及管理提升多端能力&#xff1b;数据建模配置交互升级至拖拽模式提升…

打印速度快点的打印机_瞒着领导偷偷给你们发两台打印机

前几次小粉笔组织的活动都被“投诉”&#xff01;说我们打印机太少~小粉笔心领神会&#xff0c;在这个月的活动预算费用上悄咪咪加了【两台打印机】~(看小粉笔多疼你们&#xff01;)希望知道的笔芯不要把这条推文转发给我领导(要不然你们以后就没有打印机了~哼&#xff01;)现在…

数据库误操作后悔药来了:AnalyticDB PostgreSQL教你实现分布式一致性备份恢复

简介&#xff1a; 本文将介绍AnalyticDB PostgreSQL版备份恢复的原理与使用方法。 一、背景 AnalyticDB PostgreSQL版&#xff08;简称ADB PG&#xff09;是阿里云数据库团队基于PostgreSQL内核&#xff08;简称PG&#xff09;打造的一款云原生数据仓库产品。在数据实时交互式…

与变异风险词赛跑 阿里探索AI治理网络风险

最近&#xff0c;阿里安全一线风控小二可粒发现&#xff0c;在禁售的风险防控库里&#xff0c;有人试图“上新”新品种&#xff0c;不法份子借助在社交媒体上走红的“魔法改运”等说辞&#xff0c;引人入玄学骗局。 尽量提前发现风险问题&#xff0c;提早布防是阿里安全风控部…

高效研发运维体系构建的流程和方法论

简介&#xff1a; 云计算产品大多都会与云原生发生关联&#xff0c;云原生正在重塑整个软件的生命周期。但到底什么是云原生&#xff1f;云原生带来的最大技术创新和未来机会是什么&#xff1f;围绕云原生&#xff0c;是否可以构建出一套云上的开发&运维体系&#xff0c;打…

Colima:MacOS 上的极简容器运行时和 Kubernetes

作者 | Addo Zhang来源 | 云原生指北Colima 是一个以最小化设置来在MacOS上运行容器运行时和 Kubernetes 的工具。支持 m1&#xff0c;同样也支持 Linux。Colima 的名字取自 Container on Lima。Lima 是一个虚拟机工具&#xff0c;可以实现自动的文件共享、端口转发以及 contai…

当容器应用越发广泛,我们又该如何监测容器?

简介&#xff1a; 随着容器技术蓬勃发展与落地推行&#xff0c;越来越多企业的业务运行于容器中。作为主流部署方式之一&#xff0c;容器将团队的任务和关注点分割开&#xff0c;开发团队只需关注应用程序逻辑和依赖项&#xff0c;而运维团队只需关注部署和管理&#xff0c;无需…

内含福利|CSDN携手字节跳动:云原生Meetup北京站报名热烈启动,1月8日见!

伴随云原生技术的成熟与落地&#xff0c;越来越多框架、中间件等开源项目相继涌现&#xff0c;帮助开发者和企业有效解决业务问题。2022年1月8日&#xff0c;CSDN携手字节跳动基础架构&#xff0c;将在北京举办第四场云原生线下Meetup。在这里&#xff0c;您可以与众多开源技术…

Flink CDC 2.0 正式发布,详解核心改进

简介&#xff1a; 本文由社区志愿者陈政羽整理&#xff0c;内容来源自阿里巴巴高级开发工程师徐榜江 (雪尽) 7 月 10 日在北京站 Flink Meetup 分享的《详解 Flink-CDC》。深入讲解了最新发布的 Flink CDC 2.0.0 版本带来的核心特性&#xff0c;包括&#xff1a;全量数据的并发…

unity三维地图的经纬度如何在二维地图上表示_接入C++版本recastnavigation寻路库到Unity/服务端中...

前言因为Unity版本的更新迭代&#xff0c;老版本的A*插件在新版本Unity已经无法正常使用&#xff0c;包括一些运行时代码也已经过时&#xff0c;重新接入要花费很多时间&#xff0c;干脆接入一个新的寻路方案吧。这里选择的是久负盛名的https://github.com/recastnavigation/re…

Dataphin功能:集成——如何将业务系统的数据抽取汇聚到数据中台

简介&#xff1a; 数据集成是简单高效的数据同步平台&#xff0c;致力于提供具有强大的数据预处理能力、丰富的异构数据源之间数据高速稳定的同步能力&#xff0c;为数据中台的建设打好坚实的数据基座。 数据中台是当下大数据领域最前沿的数据建设体系, 它并不是从零开始, 无中…

5G专网,路在何方?

作者 | 蜉蝣采采来源 | 无线深海话说你平常打电话、刷视频、玩游戏的4G和5G&#xff0c;一般也被叫做“公网”。这个“公”字的含义正是公开&#xff0c;公用的意思。也就是说&#xff0c;这个网络&#xff0c;不但你能用&#xff0c;你隔壁的张三也能用&#xff0c;张三的老乡…