如何用Java 8函数式风格重构HttpRequest过滤器链式调用代码?
用Java 8函数式风格重构过滤器链
嘿,你完全找对了方向!这个过滤器链式调用的场景,确实是函数组合的典型应用,用Java 8的Stream API或者Function接口的组合能力就能完美替代可变的currentRequest变量,实现无状态的函数式写法。
方案一:直接用Stream的reduce方法
这是最贴近你原有循环逻辑的写法,直接通过reduce把初始请求和所有过滤器依次串联起来:
// 初始请求作为reduce的初始值,依次应用每个filter的doFilter HttpRequest filteredRequest = filters.stream() .reduce(httpRequest, (currentReq, filter) -> filter.doFilter(currentReq), (req1, req2) -> req1); // 并行流场景下的合并逻辑,串行时可忽略但必须声明
代码解释:
- 第一个参数
httpRequest是初始值,对应你原代码里的currentRequest = httpRequest; - 第二个参数是累加器函数:把当前处理后的请求和下一个过滤器结合,输出新的请求,对应循环里的
currentRequest = filter.doFilter(currentRequest); - 第三个参数是并行流时的合并函数,这里我们用不到(因为过滤器链是串行执行的),所以返回任意一个参数即可。
方案二:先组合函数,再应用请求(更符合函数组合的思路)
如果你更倾向于一开始想的Function组合方式,可以先把每个Filter转换成Function<HttpRequest, HttpRequest>,然后用Function.andThen把它们串联成一个完整的过滤器链函数,最后一次性应用到初始请求上:
// 1. 把每个Filter转换成Function:filter.doFilter(request) 等价于 filter::doFilter // 2. 用reduce组合所有Function:identity()是恒等函数(输入即输出),andThen表示先执行前一个,再执行后一个 Function<HttpRequest, HttpRequest> filterChain = filters.stream() .map(filter -> (Function<HttpRequest, HttpRequest>) filter::doFilter) .reduce(Function.identity(), Function::andThen); // 3. 把初始请求传入组合后的函数,得到最终过滤后的请求 HttpRequest filteredRequest = filterChain.apply(httpRequest);
代码解释:
filter::doFilter是方法引用,等价于request -> filter.doFilter(request),把每个Filter转换成了一个Function;Function.identity()是初始的恒等函数,作为组合的起点;Function::andThen表示函数的顺序执行:比如有两个函数f和g,f.andThen(g)等价于x -> g(f(x)),正好符合过滤器链的执行顺序(第一个过滤器先处理请求,结果交给第二个,以此类推)。
为什么你之前的写法不对?
你之前只取了filters.get(0),相当于只应用了第一个过滤器,没有遍历所有过滤器。而上面两种方案都会遍历整个filters集合,把所有过滤器的逻辑串联起来,和原循环的效果完全一致,但没有了可变的currentRequest变量,更符合函数式编程的无状态原则。
内容的提问来源于stack exchange,提问作者cani
相关产品推荐
相关产品推荐

