如何用Java标准库实现CompletableFuture的filter功能?
问题
在使用CompletableFuture(而非Project Reactor的Mono)时,是否存在替代Project Reactor中filter()方法的方案?即当传入的谓词判断为false时,让该Future变为“空”(后续消费逻辑不执行)。
换句话说,我想要一种更优雅的写法来替代以下代码:
private void consumeResultIfPresent() { if (isConditionMet()) getCompletableFuture().thenAccept(this::consumeResult); }
理想中的优雅写法类似这样(但CompletableFuture本身没有filter方法):
private void consumeResultIfPresent_butPrettier() { getCompletableFuture().filter(v -> isConditionMet()).thenAccept(this::consumeResult); }
遗憾的是,我们的类路径中没有Project Reactor,因此只能使用Java标准并发库。让消费者自行过滤的实现方式不够优雅,并非最优解。
解决方案
Java标准库的CompletableFuture确实没有内置的filter方法,但可以通过以下几种方式实现类似效果:
1. 封装工具方法实现类filter逻辑
可以自己封装一个静态工具方法,模拟Reactor的filter行为:当条件满足时返回原结果的Future,不满足时返回一个持有null的已完成Future,后续消费逻辑只需判断null即可。
// 自定义filter工具方法 public static <T> CompletableFuture<T> filter(CompletableFuture<T> future, Predicate<? super T> predicate) { return future.thenCompose(result -> predicate.test(result) ? CompletableFuture.completedFuture(result) : CompletableFuture.completedFuture(null)); } // 调用方式接近理想写法 private void consumeResultIfPresent_butPrettier() { filter(getCompletableFuture(), v -> isConditionMet()) .thenAccept(result -> { if (result != null) { consumeResult(result); } }); }
2. 直接在thenAccept内联判断
如果不想额外封装工具类,也可以直接在thenAccept中嵌入条件判断,逻辑简洁且无额外开销:
private void consumeResultIfPresent() { getCompletableFuture() .thenAccept(result -> { if (isConditionMet()) { consumeResult(result); } }); }
3. 不推荐:利用异常控制流程
还有一种思路是当条件不满足时让Future抛出特定异常,再通过exceptionally忽略该异常,但这种方式违背了异常的语义(过滤不属于错误场景),仅作参考:
// 不推荐:滥用异常控制流程 private void consumeResultIfPresent() { getCompletableFuture() .thenCompose(result -> isConditionMet() ? CompletableFuture.completedFuture(result) : CompletableFuture.failedFuture(new NoSuchElementException())) .thenAccept(this::consumeResult) .exceptionally(ex -> { // 仅忽略过滤导致的异常 if (ex instanceof NoSuchElementException) return null; throw new CompletionException(ex); }); }
内容的提问来源于stack exchange,提问作者Cagepi
相关产品推荐
相关产品推荐

