问题
I have a bit of an odd situation that doesn’t seem to allow this peg to fit into any of the widely established CompletableFuture holes.
- Within a primary method that is evaluating returned booleans, I am wanting to allow calls to three different methods to complete asynchronously. Each of these three methods can return either a TRUE or a FALSE.
- If any return a FALSE, I want the evaluation to drop the remainder and simply return that FALSE value. The point being, it can be any of the three, not necessarily the first.
- But most importantly, I need the evaluation to wait until all three return TRUE before actually returning TRUE. This is critically important.
Right now, I am using a basic &&
chain to make this evaluation:
public boolean evaluateChecks() {
return checkOne().Join() && checkTwo().Join() && checkThree().Join();
}
However this still does things in a specific order - if checkThree()
is the first to return a FALSE value, it still has to wait until the prior two have provided their values before it gets evaluated, due to how the &&
fall-through works.
Right now all three methods return CompletableFuture<Boolean>
, but I have no problem reverting these back into normal methods in order to run a CompletableFuture
in the primary method that evaluates them.
I have looked at quite a few examples, but none seem to provide me with the functionality I need.
回答1:
Adapted from the answer by Didier L here:
- How to implement CompletableFuture.allOf() that completes exceptionally once any of the futures fail?
Instead of using exceptionally
and completeExceptionally
, use thenAccept
to complete
the CompletableFuture
returned by allOf()
.
For example, save the futures because you're about to chain actions on them:
CompletableFuture<Boolean> a = checkOne(), b = checkTwo(), c = checkThree();
Use CompletableFuture.allOf to wait for all of them to complete (presumably you're not expecting failures/exceptions) and transform the Void
result into the expected Boolean
value of true
.
CompletableFuture<Boolean> allWithFailFast = CompletableFuture.allOf(a, b, c).thenApply(__ -> a.join() && b.join() && c.join());
// if there is an exception, it'll be propagated to the future returned by thenApply
With the returned CompletableFuture
above, you can now complete
it faster if any of the original futures completes with false
.
Stream.of(a, b, c).forEach(f -> f.thenAccept(result -> {
if (!result) {
allWithFailFast.complete(false);
}
}));
Depending on the order of completions and their result, either the allOf
future will complete first with a result of evaluating the futures or one of the futures will return false
and cause the allWithFailFast
to complete with false
.
If multiple futures complete with false
, only the first call to
allWithFailFast.complete(false);
will do anything, the others will essentially be ignored.
来源:https://stackoverflow.com/questions/58999254/completablefuture-how-to-return-first-false-or-wait-until-all-are-completed-to-r