背??景正确。我仍在从事XXXX项目并与第三方联系。不同的是,这次我处理的是我自己的业务逻辑。在开发过程中遇到这样一个问题:表结构:一个主表A,一个关联表B,表A存储表B记录的状态。场景:第一步创建主表数据并插入A表;第二步是调用第三方接口插入B表,更新A表的状态,此时大家应该想到在进行第二步的时候需要做好数据的幂等性。这种情况下,会出现以下几种情况:1、B表中没有A表关联的数据,此时需要调用第三方接口,插入B表,更新A表的状态同时;与表关联的数据;A表状态为processing:直接返回wordprocessing;A表状态为处理成功:直接返回success字样;A表状态处理失败:此时需要调用第三方接口,更新B表的同时更新A表的状态;代码实现首先,我写了伪代码Bb=this.baseMapper.selectOne(queryWrapper);if(b!=null){Stringstatus=b.getStatus();if(Objects.equals(Constants.STATUS_ING,status)){return"Processing";}elseif(Objects.equals(Constants.STATUS_SUCCESS,status)){return"Processingsuccessfully";}//操作失败//请求第一个三方接口并解析响应结果......if(ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())){...//更新B表操作bb.setStatus(Constants.STATUS_ING);mapper.updateById(bb);//更新B表操作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);}}不知道细心的小伙伴发现没有recoB表中的rds,状态为“failure”,不存在B表,除了插入B表或更新B表的操作外,其余操作相同。如果我们要抽取公共部分,发现比较散乱,最好不要抽取,但是有很多重复的代码没有抽取代码,不符合我的风格。所以我联系了消费者界面。更改后的伪代码Bb=this.baseMapper.selectOne(queryWrapper);if(b!=null){Stringstatus=b.getStatus();if(Objects.equals(Constants.STATUS_ING,status)){return"inprocess";}elseif(Objects.equals(Constants.STATUS_SUCCESS,status)){return"处理成功";}//操作失败getResponse(dto,response,s->mapper.updateById(s));}else{getResponse(dto,response,s->mapper.updateById(s));}publicvoidgetResponse(DTOdto,Responseresponse,Consumerconsumer){//请求第三方接口并解析响应结果......如果(ReturnInfoEnum.SUCCESS.getCode().equals(parse.getCode())){...bb.setStatus(Constants.STATUS_ING);consumer.accept(bb);//更新A表状态a.setStatus(Constants.STATUS_ING);aMapper.updateById(a);}}看到这里,如果大家已经看懂了,那么恭喜你,说明你已经掌握了Consumer的使用。如果你还有一丝疑惑,那么继续往下看,我们将介绍四种常用的功能接口。函数式接口那么什么是函数式接口呢?函数式接口是只有一个抽象方法(Object的方法除外),但可以有多个非抽象方法的接口。它表达了一个逻辑单一的功能。@FunctionalInterface@FunctionalInterface注解用于表明该接口是函数式接口。它有助于及早检测功能接口中存在的或由接口继承的不适当的方法声明。如果一个接口被注解了这个注解但实际上不是函数式接口,编译时就会报错。Consumer我们一般称之为“消费者”,意思是接受单个输入参数但不返回结果的操作。与其他功能接口不同,Consumer需要通过副作用来操作。那么什么是副作用呢?让我谈谈我理解的副作用。副作用实际上是函数是否修改了其范围之外的资源。如果有,则称为副作用,否则表示没有副作用。比如修改全局变量,修改入参引用的对象等。@FunctionalInterfacepublicinterfaceConsumer{/***对给定的参数执行这个操作。*/voidaccept(Tt);/****返回一个组合的Consumer,依次执行这个操作,再执行after操作。*如果执行任何一个操作都会抛出异常,它将被转发给组合操作的调用者。*如果执行此操作会抛出异常,则不会执行after操作。*/defaultConsumerandThen(Consumerafter){Objects.requireNonNull(after);return(Tt)->{accept(t);after.accept(t);};}}在我们的例子中在遇到的场景中,我们只需要将要执行的逻辑方法作为参数传入getResponse(),然后执行该方法中的accept()方法进行消费即可。如果还是不明白,我们可以转换成匿名内部类的调用方法。getResponse(dto,response,newConsumer(){@Overridepublicvoidaccept(Bbb){mapper.insert(bb);});当调用accept()方法时,会调用匿名内部类的方法,也就是我们传入getResponse()的逻辑方法。供应商一般称为“生产商”。它没有参数输入,但可以返回结果,它是结果的提供者。@FunctionalInterfacepublicinterfaceSupplier{/***Getaresult*/Tget();}可以举个简单的例子感受下:Optionaloptional=Optional.empty();optional.orElseGet(()->Math.random());//orElseGet方法的源码,其中使用了get方法publicTorElseGet(Supplierother){returnvalue!=null?value:other.get();}函数我称之为“conversion"Order",表示函数接收一个参数,处理后返回一个结果。@FunctionalInterfacepublicinterfaceFunction{/***输入T类型的参数,函数表达式计算后,返回结果oftypeR*/Rapply(Tt);/***返回一个组合函数,首先将参数应用到before函数,然后将结果应用到当前函数,返回最终结果。*如果对的求值任一函数引发异常,它被转发给组合函数的调用者。*/defaultFunctioncompose(Functionbefore){Objects.requireNonNull(before);return(Vv)->apply(before.apply(v));}/***返回组合函数,先将参数应用到当前函数,再将结果应用到after函数,并返回最终结果。*如果任一函数的评估引发异常,则将其转发给组合函数的调用者。*/defaultFunctionandThen(Functionafter){Objects.requireNonNull(after);return(Tt)->after.apply(apply(t));}/***返回一个始终返回其输入参数的函数。*/staticFunctionidentity(){return->t;}}我们使用的lambda表达式比较多,所以简单演示一下:@Data@AllArgsConstructorpublicclassTeacher{privateStringname;privateintage;}publicclassTeacherTest{publicstaticvoidmain(String[]args){Listlist=Arrays.asList(newTeacher("张三",25),newTeacher("李四",28),newTeacher("王舞",18));Listcollect=list.stream().map(item->item.getName()).collect(Collectors.toList());System.out.println(collect);}}map接收的参数是Function类型,item是传入参数,item.getName()是返回的处理结果,最终输出的结果是[张三,李四,王五]谓词,我们称之为“判断者”,通过接收参数T来返回布尔结果。@FunctionalInterfacepublicinterfacePredicate{/***接收一个参数,判断这个参数是否匹配某个规则,匹配成功返回true,匹配失败返回false*/booleantest(Tt);/***receiveaPredicate类型参数,利用当前函数和其他函数的逻辑判断参数t是否符合规则,成功则返回true,当前函数返回false则返回false*如果当前函数返回false,则其他函数不会执行计算*Predicate评估期间引发的任何异常都将转发给调用者*/defaultPredicateand(Predicateother){Objects.requireNonNull(other);return(t)->test(t)&&other.test(t);}/***运算后返回当前Predicate取反Predicate*/defaultPredicatenegate(){return(t)->!test(t);}/***接收一个Predicate类型的参数,使用当前函数和其他函数逻辑或者判断参数是否ert匹配规则,成功返回true,失败返回false*如果当前函数返回true,其他函数不求值*Predicate求值过程中抛出的任何异常都会转发给调用者*/defaultPredicateor(Predicateother){Objects.requireNonNull(other);return(t)->test(t)||other.test(t);}/***静态方法:传入一个参数生成Predicate并调用test()方法object->targetRef.equals(object)函数**/staticPredicateisEqual(ObjecttargetRef){return(null==targetRef)?Objects::isNull:object->targetRef。equals(object);}}相信每个人这个功能接口在编码过程中经常遇到。举个例子:publicstaticvoidmain(String[]args){Listlist=Arrays.asList(newTeacher("张三",25),newTeacher("李四",28),newTeacher("王舞",18));list=list.stream().filter(item->item.getAge()>25).collect(Collectors.toList());list.stream().forEach(item->System.out.println(item.getName()));}其中filter()的参数是Predicate类型,返回结果是:李四看到这里,我们经常看到的四个函数接口已经介绍过了。说实话,函数式接口我已经看过好几遍了,尤其是Consumer和Supplier。当时只是在脑子里学,并没有应用到具体的项目中。下次遇到它的时候,我还是一脸懵逼。不知道你有没有这种感觉。所以我们需要总结经验和教训,一定要理解代码的原理,然后多敲几下,尝试应用到自己的项目中,提高自己的编码能力。本文转载自微信公众号“阿Q说码”,可通过以下二维码关注。转载本文请联系阿Q获取代码公众号。