当前位置: 首页 > 后端技术 > Node.js

从源码的角度学习java函数式编程

时间:2023-04-04 01:34:53 Node.js

Java函数式编程简单来说,函数式编程就是用注解@FunctionalInterface修饰的接口。@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)public@interfaceFunctionalInterface{}//jdk中的LongToIntFunction相当于一个接口@FunctionalInterfacepublicinterfaceLongToIntFunction{/***将这个函数应用于给定的参数。**@paramvaluethefunctionargument*@returnthefunctionresult*/intapplyAsInt(longvalue);}//这个接口可以直接传入函数直接使用//以jdk中的LongPipeline为例@Overridepublic最终IntStreammapToInt(LongToIntFunction映射器){Objects.requireNonNull(映射器);返回新的IntPipeline.StatelessOp(this,StreamShape.LONG_VALUE,StreamOpFlag.NOT_SORTED|StreamOpFlag.NOT_DISTINCT){@OverridesSintSinksink){返回新的Sink。ChainedLong(sink){@Overridepublicvoidaccept(longt){下游.accept(mapper.applyAsInt(t));}};那么,如何实现函数是一个编程接口呢?之前讲注解的时候,提到编译器会识别jdk内置的元注解,并赋予被注解修饰的对象编译器预定义的行为。但是,接口始终是接口,没有实际行为,实际的行为还是需要具体的实现类来定义,那么我们就来看看函数式接口应该如何实现。以Springboot中的函式接口TargetServerConnection为例@FunctionalInterfacepublicinterfaceTargetServerConnection{/***打开一个到目标服务器的连接并指定超时时间。*@paramtimeout读取超时*@returna{@linkByteChannel}提供对服务器的读/写访问*@throwsIOException在I/O错误的情况下*/ByteChannelopen(inttimeout)throwsIOException;}//现实类SocketTargetServerConnection.java中的打开方法@OverridepublicByteChannelopen(intsocketTimeout)throwsIOException{SocketAddressaddress=newInetSocketAddress(this.portProvider.getPort());logger.trace(LogMessage.format("在%s上打开到目标服务器的隧道连接",address));SocketChannel通道=SocketChannel.open(地址);channel.socket().setSoTimeout(socketTimeout);returnnewTimeoutAwareChannel(channel);}//在HttpTunelServer中使用protectedServerThreadgetServerThread()throwsIOException{synchronized(this){if(this.serverThread==null){ByteChannelchannel=this.serverConnection.open(this.longPollTimeout);this.serverThread=newServerThread(channel);this.serverThread.start();}返回this.serverThread;}}可以看到,这种写法是传统的接口实现方式,所以我们说函数式接口就是接口,并不是什么高级的语法糖,@FunctionalInterface注解并没有提供额外的功能,只是通过这个注解修改接口,让编译器知道,然后判断接口定义是否符合函数式接口的定义规则那么,如何使用函数式接口呢?这个问题不好回答,先看下面的代码@FunctionalInterfacepublicinterfaceExitCodeExceptionMapper{intgetExitCode(Throwableexception);}这是springboot框架中定义的获取退出码的函数式接口//SpringApplicationTest.java@BeanExitCodeExceptionMapperexceptionMapper(){return(exception)->{if(exceptioninstanceofIllegalStateException){return11;}返回0;};}//SpringApplication.javaprivateintgetExitCodeFromMappedException(ConfigurableApplicationContextcontext,Throwableexception){if(context==null||!context.isActive()){return0;}ExitCodeGenerators生成器=newExitCodeGenerators();集合beans=context.getBeansOfType(ExitCodeExceptionMapper.class).values();generators.addAll(异常,bean);returngenerators.getExitCode();}在使用函数式接口的地方,我们从第一个例子可以知道,函数式接口解释的类型等同于其唯一方法的返回值所代表的类型。第二个例子告诉我们,函数式接口不一定非要实现才能获取实际行为,也可以通过反射获取。源码分析完毕,我们来实现一个例子//定义一个函数式接口Demo1.java@FunctionalInterfacepublicinterfaceDemo1{StringgetName(Integercode);}//implementclassDemo2.javapublicclassDemo2implementsDemo1{@OverridepublicStringgetName(整数代码){StringBuilderbuilder=newStringBuilder();returnbuilder.append("mynameis").append(code).append("!").toString();}}//CallerDemo3.javapublicclassDemo3{publicstaticvoidmain(String[]args){//在使用过程中实例化Demo1demo1=newDemo1(){@OverridepublicStringgetName(Integercode){returnnewStringBuilder().append("我的名字是").append(code).append("!").toString();}};System.out.println(demo1.getName(1));System.out.println(demo1.getName(2));//通用接口Demo1demo2=newDemo2();System.out.println(demo2.getName(1));System.out.println(demo2.getName(2));//简单的函数式编程Demo1demo3=code->{returnnewStringBuilder().append("mynameis").append(code).append("!").toString();};System.out.println(demo3.getName(1));System.out.println(demo3.getName(2));}}以上三个打印结果是一样的,也就是说对于函数式接口,我们可以直接使用语法Demo1demo3=code->{returnnewStringBuilder().append("mynameis").append(code).append("!").toString();};定义其功能体的好处简洁稳重的炸鸡麻辣鸡原创文章,转载请注明出处