WebFlux也不是一帮人拍脑门突然发明的,它是一个漫长的过程,WebFlux本身在逐步完善,各种配套工具理论也在逐步发展。 因此当想写WebFlux的时候,发现没法直接从WebFlux本身开始写起,对于很多没有接触过函数式编程的人来说,上来就整WebFlux还是有一些挑战的,想来想去,我觉得还是先来和大家捋一捋JDK8中的一些旧玩意。 虽然JDK8发布距今已经七八年了,但是相信还是有相当多小伙伴用着JDK8,写着JDK6的代码。所以我们有必要回顾一下JDK8,也算是我们学习WebFlux的一些前置知识。 好啦,开整吧。1。Lambda表达式的四种写法 JDK8中引入了Lambda,这个大家都知道,虽然现在JDK都出到16了,但是老实说,项目中的Lambda表达式似乎还是很少有人用。有的团队技术风格激进,可能会见到很多Lambda,但是大部分技术团队还是比较保守的。今天为了学习WebFlux,我们还是先来回顾一下Lambda表达式的几种写法。 先来说说,如果要用Lambda,必须是只有一个需要强制实现方法的接口,我们可以使用FunctionalInterface注解去标记该接口:FunctionalInterfaceinterfaceICalculator{intsquare(inti);} 此时如果该接口中有多个空方法,编译期间就会报错。 现在我们建议尽量将一个接口设计的小一些,这样也满足单一职责原则。 不过JDK8中引入了default方法,就是自带默认实现的那种,自带默认实现的方法可以有多个,这个并不影响Lambda,并且FunctionalInterface注解也不会去检查默认方法的数量。1。1单个参数的 如果只是一个参数,那么直接写参数即可,例如如下代码:interfaceICalculator{intsquare(inti);}publicclassLambdaDemo01{publicstaticvoidmain(String〔〕args){ICalculatoriciii;intsquareic。square(5);System。out。println(squaresquare);}} 当函数只有一个参数的时候,直接写即可,不需要添加()。1。2多个参数 多个参数的话,就需要写上()了,以SpringSecurity中登录成功的回调为例(不了解SpringSecurity的小伙伴可在公号后台回复ss):。defaultLogoutSuccessHandlerFor((req,resp,auth){resp。setContentType(applicationjson;charsetutf8);MapString,ObjectresultnewHashMap();result。put(status,200);result。put(msg,使用logout1注销成功!);ObjectMapperomnewObjectMapper();Stringsom。writeValueAsString(result);resp。getWriter()。write(s);},newAntPathRequestMatcher(logout1,GET))。defaultLogoutSuccessHandlerFor((req,resp,auth){resp。setContentType(applicationjson;charsetutf8);MapString,ObjectresultnewHashMap();result。put(status,200);result。put(msg,使用logout2注销成功!);ObjectMapperomnewObjectMapper();Stringsom。writeValueAsString(result);resp。getWriter()。write(s);},newAntPathRequestMatcher(logout2,POST))。and()。csrf()。disable(); 这种情况,方法有多个参数,此时使用Lambda表达式就需要加上()。1。3要写参数类型的 正常来说用Lambda时候不需要写上参数类型,但是如果你需要写,就要加上(),还是上面那个例子,如下:interfaceICalculator{intsquare(inti);}publicclassLambdaDemo01{publicstaticvoidmain(String〔〕args){ICalculatoric(inti)ii;intsquareic。square(5);System。out。println(squaresquare);}}1。4方法体不止一行的 如果方法体不止一行,需要用上{},如果方法体只有一行,则不需要{},参考上面2、3。2。函数接口 JDK8中自带了函数式接口,使用起来也非常方便。2。1基本应用 我们先来看一个简单的例子。 假设我有一个打招呼的接口SayHello,SayHello接口中只有一个sayHello方法,然后在User类中调用该接口对应的方法,最终用法如下:FunctionalInterfaceinterfaceSayHello{StringsayHello(Stringname);}classUser{privateStringusername;publicStringgetUsername(){returnusername;}publicvoidsetUsername(Stringusername){this。usernameusername;}publicStringsay(SayHellosayHello){returnsayHello。sayHello(this。username);}}publicclassLambdaDemo02{publicstaticvoidmain(String〔〕args){UserusernewUser();user。setUsername(javaboy);Stringsayuser。say((username)hellousername);System。out。println(saysay);}} 分析main方法中的调用过程之后,我们发现,在调用时最核心的是如下一行代码:(username)hellousername 在这段代码中,我们只关心方法的输入和输出,其他的都不是我所考虑的,为了一个简单的输入输出,我还要额外定义一个接口,这显然不太划算。 JDK8中提供了函数接口,可以帮助我们简化上面的接口定义。如下:classUser2{privateStringusername;publicStringgetUsername(){returnusername;}publicvoidsetUsername(Stringusername){this。usernameusername;}publicStringsay(FunctionString,StringsayHello){returnsayHello。apply(this。username);}}publicclassLambdaDemo03{publicstaticvoidmain(String〔〕args){User2user2newUser2();user2。setUsername(javaboy);Stringsayuser2。say((username)hellousername);System。out。println(saysay);}} 可以用FunctionString,String代替我们前面的接口定义,这里有两个泛型,第一个泛型表示接口输入的参数类型,第二个泛型表示接口输出的参数类型,而且大家注意,我们最终main方法中的调用方式是不变的。有了Function函数之后,以后我们就不需要定义一些简单的接口了。 而且Function函数还支持链式操作,如下:publicclassLambdaDemo03{publicstaticvoidmain(String〔〕args){User2user2newUser2();user2。setUsername(javaboy);FunctionString,Stringfunc(username)hellousername;Stringsayuser2。say(func。andThen(s你好s));System。out。println(saysay);}}2。2其他函数接口 接下来我们来看看这些函数接口。2。2。1UnaryOperator 当输入输出类型相同时,可以使用UnaryOperator函数接口,例如我们上面的代码,修改之后如下:classUser2{privateStringusername;publicStringgetUsername(){returnusername;}publicvoidsetUsername(Stringusername){this。usernameusername;}publicStringsay(UnaryOperatorStringsayHello){returnsayHello。apply(this。username);}}publicclassLambdaDemo03{publicstaticvoidmain(String〔〕args){User2user2newUser2();user2。setUsername(javaboy);UnaryOperatorStringfunc(username)helloousername;Stringsayuser2。say(func);System。out。println(saysay);}}2。2。2Predicate Predicate输入一个T类型的参数,输出一个boolean类型的值。 举一个简单的例子,例如如下代码,我们定义一个List集合中存放着用户姓名,现在要过滤出所有姓张的用户,代码如下:publicclassLambdaDemo04{publicstaticvoidmain(String〔〕args){ListStringnamesArrays。asList(张三,里斯,张五);ListStringlistnames。stream()。filter(ss。startsWith(张))。collect(Collectors。toList());for(Strings:list){System。out。println(ss);}}} filter中传入的就是一个Predicate函数接口,这个接口接收String类型的数据,返回一个boolean。 注意 一些常用类型的函数接口,JDK中直接提供了相关的类供我们使用,例如Predicate可以用IntPredicate代替;Consumer可以用IntConsumer代替。2。2。3Consumer 看名字就知道,这个是消费数据,只有输入没有输出。 例如集合的遍历就可以使用Consumer函数接口。publicclassLambdaDemo04{publicstaticvoidmain(String〔〕args){ListStringnamesArrays。asList(张三,里斯,张五);names。stream()。forEach(sSystem。out。println(s));}}2。2。4Supplier Supplier刚好和Consumer相反,它只有输出没有输入。有的时候我们的工厂方法没有输入只有输出,这个时候就可以考虑使用Supplier(如果有输入参数,则可以考虑使用Function函数接口)。SupplierConnectionsupplier(){Connectionconnull;try{conDriverManager。getConnection(,,);}catch(SQLExceptione){e。printStackTrace();}returncon;};Connectionconnectionsupplier。get();3。小结 其实WebFlux前置知识还是蛮多的,今天先聊这些吧,我们后面继续。 转载自:江南一点雨 原文链接: https:mp。weixin。qq。comsDiaDtt0nW38RKUqQSNKj4Q