当前位置: 首页 > 科技观察

一起来学习一下WebFlux的前置知识

时间:2023-03-15 15:58:13 科技观察

最近太忙了,发帖频率有点不稳定。理解万岁。我之前告诉过你我们需要更新WebFlux。在学习WebFlux之前,我们先来学习一些前置知识。罗马不是一天建成的。WebFlux并不是一群人突然发明的。这是一个漫长的过程。WebFlux本身在逐渐完善,各种配套工具/理论也在逐渐发展。所以当宋哥想要写WebFlux的时候,发现不能直接从WebFlux本身开始写。对于很多没有接触过函数式编程的人来说,完成WebFlux仍然是一个挑战。想来想去,还是觉得还是先看看JDK8中的一些老东西吧。虽然JDK8发布已经七八年了,但是相信还是有不少小伙伴在使用JDK8,写JDK6的代码。所以我们有必要复习一下JDK8,可以算是我们学习WebFlux的一些前置知识。好的,让我们开始吧。一、Lambda表达式的四种写法Lambda是在JDK8中引入的。每个人都知道这一点。虽然JDK现在16了,但是说实话,Lambda表达式在项目中好像很少用到。有的团队技术风格比较激进,可能会看到很多Lambda,但是大部分技术团队比较保守。今天为了学习WebFlux,我们先来回顾一下Lambda表达式的几种写法。首先,如果要使用Lambda,必须只有一个接口需要强制实现方法。我们可以使用@FunctionalInterface注解来标记接口:@FunctionalInterfaceinterfaceICalculator{intsquare(inti);}这时候,如果接口Empty方法中有多个接口,编译时就会报错。现在我们建议接口尽量设计的小一些,这样也符合单一职责的原则。但是,JDK8中引入的默认方法是具有自己的默认实现的方法。可以有多个方法及其自己的默认实现。这不会影响Lambda,@FunctionalInterface注解不会检查默认方法的数量。1.1如果单个参数只是一个参数,那么直接写参数,例如下面的代码:=ic.square(5);System.out.println("square="+square);}}当函数只有一个参数时,直接写就可以了,不用加()。1.2多个参数如果有多个参数,需要写()。以SpringSecurity中登录成功的回调为例(不了解SpringSecurity的朋友可以在公众号后台回复ss):.defaultLogoutSuccessHandlerFor((req,resp,auth)->{resp.setContentType("application/json;charset=utf-8");Mapresult=newHashMap<>();result.put("status",200);result.put("msg","注销成功使用logout1!");ObjectMapperom=newObjectMapper();Strings=om.writeValueAsString(result);resp.getWriter().write(s);},newAntPathRequestMatcher("/logout1","GET")).defaultLogoutSuccessHandlerFor((req,resp,auth)->{resp.setContentType("application/json;charset=utf-8");Mapresult=newHashMap<>();result.put("status",200);result.put("msg","logoutsuccessfullyusinglogout2!");ObjectMapperom=newObjectMapper();Strings=om.writeValueAsString(result);resp.getWriter().write(s);},newAntPathRequestMatcher("/logout2","POST")).and().csrf().disable();这种情况下,如果方法有多个参数,此时需要加上()才能使用Lambda表达式。上面(),或者上面的例子,如下:interfaceICalculator{intsquare(inti);}publicclassLambdaDemo01{publicstaticvoidmain(String[]args){ICalculatic=(inti)->i*i;intsquare=ic.square(5);System.out.println("square="+square);}}1.4如果方法体超过一行,需要使用{},如果方法体只有一行,则不需要{},参考上面2、32.函数式接口JDK8自带函数式接口,使用起来非常方便。2.1基本应用先来看一个简单的例子。假设我有一个打招呼的接口SayHello,而SayHello接口中只有一个sayHello方法,然后在User类中调用该接口对应的方法。最终用法如下:@FunctionalInterfaceinterfaceSayHello{StringsayHello(Stringname);}classUser{privateStringusername;publicStringgetUsername(){returnusername;}publicvoidsetUsername(Stringusername){this.("javaboy");Stringsay=user.say((username)->"hello"+username);System.out.println("say="+say);}}分析完main方法中的调用流程,我们发现调用的核心是下面这行代码:(username)->"hello"+username在这段代码中,我们只关心方法的输入输出,其他的不是我考虑的.为了简单,我不得不为输入和输出定义一个额外的接口,这显然不符合成本效益。JDK8中提供了函数式接口,可以帮助我们简化上面的接口定义。如下:publicstaticvoidmain(String[]args){User2user2=newUser2();user2.setUsername("javaboy");Stringsay=user2.say((username)->"hello"+username);System.out.println("say="+say);}}您可以使用Function来替换我们之前的接口定义。这里有两种通用类型。第一个泛型表示接口输入的参数类型,第二个泛型表示接口输出的参数类型。键入,请注意我们最后的main方法中的调用方法保持不变。有了Function功能,以后我们就不用定义一些简单的接口了。并且Function函数也支持链式操作,如下:"hello"+username;Stringsay=user2.say(func.andThen(s->"Hello"+s));System.out.println("say="+say);}}2.2其他函数接口输入参数返回类型描述UnaryOperatorTT一元函数,输入输出类型相同PredicateTboolean断言ConsumerT/消费一个数据,只有输入没有输出FunctionTR输入T返回R,有输入有输出Supplier/T提供一个数据,无输入只输出BiFunction(T,U)R两个输入参数BiPredicate(L,R)boolean两个输入参数BiConsumer(T,U)void两个输入参数BinaryOperator(T,T)T二元函数,输入输出类型相同接下来我们来看看这些函数接口。2.2.1UnaryOperator当输入输出类型相同时,可以使用UnaryOperator函数接口,比如我们上面的代码,修改后如下:classUser2{privateStringusername;publicStringgetUsername(){returnusername;}publicvoidsetUsername(Stringusername){this.username=username;}publicStringsay(UnaryOperatorsayHello){returnsayHello.apply(this.username);}}publicclassLambdaDemo03{publicstaticvoidmain(String[]args){User2user2=newUser2();user2.setUsername("javaboy");UnaryOperatorfunc=(username)->"hello"+username;Stringsay=user2.say(func);System.out.println("say="+say);}}2.2.2PredicatePredicate输入aT类型参数并输出一个布尔类型的值。举个简单的例子,比如下面的代码,我们定义了一个List集合来存储用户名,现在我们要过滤掉所有姓张的用户,代码如下:publicclassLambdaDemo04{publicstaticvoidmain(String[]args){Listnames=Arrays.asList("张三","里斯","张武");Listlist=names.stream().filter(s->s.startsWith("张")).collect(Collectors.toList());for(Strings:list){System.out.println("s="+s);}}}filter中传入的是Predicate函数接口,接收String类型的数据并返回一个布尔值。注意一些常见的函数接口类型。JDK直接提供了相关的类供我们使用。例如,Predicate可以被IntPredicate代替;Consumer可以替换为IntConsumer。2.2.3Consumer看名字就知道是消费数据,只有输入没有输出。比如集合的遍历可以使用Consumer函数接口。publicclassLambdaDemo04{publicstaticvoidmain(String[]args){Listnames=Arrays.asList("张三","Rees","张武");names.stream().forEach(s->System.out.println(s));}}2.2.4SupplierSupplier与Consumer正好相反,只有输出没有输入。有时候我们的工厂方法没有输入只有输出。这时候可以考虑使用Supplier(如果有入参可以考虑使用Function函数接口)。Suppliersupplier=()->{Connectioncon=null;try{con=DriverManager.getConnection("","","");}catch(SQLExceptione){e.printStackTrace();}returncon;};Connectionconnection=supplier.get();3.总结其实关于WebFlux的前期知识还是挺多的。今天先说这些,以后再继续。本文转载自微信公众号“江南的一场小雨”,可通过以下二维码关注。转载本文请联系江南一点鱼公众号。