如何实现类似CompletableFuture.anyOf()但返回首个非null结果的功能?
如何实现类似CompletableFuture.anyOf()但返回首个非null结果的功能?
当然可以做到!我来给你分享一个实用的实现思路和代码示例:
核心思路其实很简单:CompletableFuture.anyOf()会响应第一个完成的future,不管结果是不是null。那我们只需要给每个原始的future做一层“包装”——让它们只有在返回非null结果时才会“完成”,如果返回null,就让这个包装后的future暂时处于未完成状态,这样它就不会被anyOf()选中。
第一步:写一个工具方法包装原始Future
我们可以封装一个方法,把每个原始Future转换成符合要求的新Future:
private static <T> CompletableFuture<T> wrapNonNullFuture(CompletableFuture<T> originalFuture) { return originalFuture.thenCompose(result -> { // 如果结果非null,直接用这个结果完成新Future if (result != null) { return CompletableFuture.completedFuture(result); } else { // 如果结果是null,返回一个永远不会主动完成的Future // 这样它就不会被后续的anyOf()选中 return new CompletableFuture<>(); } }); }
第二步:包装所有Future并调用anyOf()
接下来把你所有的原始Future都用这个方法包装一遍,再传给anyOf(),这样得到的就是第一个返回非null结果的Future了:
// 你的原始Future列表 CompletableFuture<String> comp1 = CompletableFuture.supplyAsync(() -> { // 模拟可能返回null的业务逻辑 return Math.random() > 0.5 ? "来自Comp1的有效结果" : null; }); CompletableFuture<String> comp2 = CompletableFuture.supplyAsync(() -> { return Math.random() > 0.5 ? "来自Comp2的有效结果" : null; }); // 可以添加更多comp3、comp4... // 包装所有原始Future CompletableFuture<?>[] nonNullFutures = Stream.of(comp1, comp2) .map(YourClassName::wrapNonNullFuture) .toArray(CompletableFuture<?>[]::new); // 现在调用anyOf(),拿到的就是首个非null的结果 CompletableFuture<Object> firstNonNullResult = CompletableFuture.anyOf(nonNullFutures);
额外补充:处理极端情况
如果所有原始Future都返回null,那上面的firstNonNullResult会一直处于未完成状态,这显然不太友好。我们可以给它加个超时处理,避免无限等待:
CompletableFuture<Object> resultWithTimeout = CompletableFuture.anyOf(nonNullFutures) .orTimeout(5, TimeUnit.SECONDS) // 5秒超时 .exceptionally(ex -> { // 超时或其他异常时的兜底处理,比如返回默认值 return "默认兜底结果"; });
另外,如果你的原始Future可能抛出异常,还可以在包装方法里加上异常处理,把异常也当成“无效结果”(即null)来处理:
private static <T> CompletableFuture<T> wrapNonNullFutureWithExceptionHandling(CompletableFuture<T> originalFuture) { return originalFuture.handle((result, exception) -> { // 如果有异常,直接返回null,后续逻辑会把它当成无效结果 if (exception != null) { return null; } return result; }).thenCompose(result -> { if (result != null) { return CompletableFuture.completedFuture(result); } else { return new CompletableFuture<>(); } }); }
这样调整后,不管是返回null还是抛出异常的Future,都不会干扰我们获取第一个有效(非null)的结果啦。
内容来源于stack exchange
相关产品推荐
相关产品推荐

