Java CompletableFuture 流式编程最佳实践?
資深大佬 : nthin0 0
- 虽然在很多地方看到有人说 java8 里的 CompletableFuture 是个残品,忍不住还是想在项目中用用,然后就碰到几个很蛋疼的问题
重试
- 在 CompletableFuture 里调 rest 接口,发现没有自带的重试机制,比如根据响应码重试,根据 exception 类型重试,根据特定的响应内容重试。。。
- 解决:引入第三方框架Failsafe,目前跟 CompletableFuture 搭配使用感觉还不错,需要的功能都有了
任务顺序
- 有时候想在一个任务处阻塞住,等其他任务完成;有时候需要多个任务并发完成。目前没办法在一条流式语句中完成所有任务,需要拆成多个 CompletableFuture,再进行组合
- “一条流式任务”指类似这种
CompletableFuture.supplyAsync(...) .thenCompose(...) .thenApply(...) .thenRun(...) .thenxxx(...) .whenComplete((v, ex) -> ...); - 用.thenCompose(v -> CompletableFuture.supplyAsync(() -> doWork(v), executor))时任务会停下等 doWork 完成,用.thenRun(() -> doWork2())的时候不会。。。
- 这个地方应该是我理解还不够,没有理清楚 thenCompose 、thenCombine 、thenAccept 、thenRun 、thenApply 中哪些是能够“阻塞”的,哪些是不能的
一条流式语句中目前没解决的问题
whenComplete
- 在一条流式语句中完成所有任务就不用写多个 whenComplete,把所有任务中出现的异常都能放到一个 whenComplete 统一处理。
需要多个参数参与任务流转的问题
String doWork1(){} Integer doWork2(String work1Result){} String finalWork(String work1Result, Integer work2Result){} CompletableFuture.supplyAsync(doWork1) .thenCompose(doWork2) .thenRun(someWork) //someWork 中并不需要 work1 和 work2 的结果 .thenCompose(finalWork)
-
但是为了能够将 work1 和 work2 的结果传递到 finalWork,就必须要在 someWork 中强行加上入参,再原样放到返回中
-
解决:所有方法一律入参 tuple,返回 tuple,方法中只取需要的值,其他值放在 tuple 中往后流转。但是方法显得不够模块,很冗余,而且对后面维护代码的人很不友好
- vavr框架中的 tuple2 tuple3…(通过 map1 、update1 )或者 either 还是比较好用的,弥补了一部分原生 java 的缺陷
-
感觉最近对函数式编程、函子这些比较入迷,有大佬能推荐一下 java8 中使用 CompletableFuture 的正确姿势吗,或者关于函数式编程比较好的教程
大佬有話說 (16)