I have some CompletableFuture
s and I want to run them in parallel, waiting for the first that returns normally.
I know I can use CompletableFuture.anyOf
to wait for the first to return, but this will return normally or exceptionally. I want to ignore exceptions.
List<CompletableFuture<?>> futures = names.stream().map(
(String name) ->
CompletableFuture.supplyAsync(
() ->
// this calling may throw exceptions.
new Task(name).run()
)
).collect(Collectors.toList());
//FIXME Can not ignore exceptionally returned takes.
Future any = CompletableFuture.anyOf(futures.toArray(new CompletableFuture<?>[]{}));
try {
logger.info(any.get().toString());
} catch (Exception e) {
e.printStackTrace();
}
Considering that:
One of the foundations of the philosophy of Java is to prevent or discourage bad programming practices.
(To what degree it has been successful in doing so is the subject of another debate; the point still stands that this has undeniably been one of the primary aims of the language.)
Ignoring exceptions is a very bad practice.
An exception should always be either rethrown to the layer above, or handled, or at the very least reported. Specifically, an exception should never be silently swallowed.
Errors should be reported at the earliest time possible.
for example, see the pains the runtime goes through in order to provide fail fast iterators which throw a ConcurrentModificationException if the collection is modified while iterating.
Ignoring an exceptionally completed
CompletableFuture
means that a) you are not reporting an error at the earliest time possible, and b) you are likely planning to not report it at all.The inability to simply wait for the first non-exceptional completion and instead having to be bothered by exceptional completions does not impose any significant burden, because you can always remove the exceptionally completed item from the list, (while at the same time not forgetting to report the failure, right?) and repeat the wait.
I would therefore not be surprised if the sought-for feature is intentionally missing from Java, and I would be willing to argue that it is rightfully missing.
(Sorry Sotirios, no canonical answer.)
Will this work? Returns a stream of all the futures that completed normally, and returns one of them.
Well, that is a method what should be supported by the framework. First, I thought CompletionStage.applyToEither does something similar, but it turns out it doesnt. So I came up with this solution:
To see it in action, here is some usage:
You may use the following helper method:
which you can use like this, to demonstrate that it will ignore earlier exceptions but return the first provided value:
One disadvantage of this solution is that it will never complete if all futures complete exceptionally. A solution, that will provide the first value if there is a successful computation but fail exceptionally if there is no successful computation at all, is a bit more involved:
It utilizes the fact that
allOf
’s exceptionally handler is only invoked after all futures have completed (exceptionally or not) and that a future can be completed only once (letting special things likeobtrude…
aside). When the exceptionally handler is executed, any attempt to complete the future with a result has been done, if there was one, so the attempt to complete it exceptionally only succeeds, if there was no previous successful completion.It can be used exactly the same way as the first solution and only exhibit different behavior if all computations fail, e.g.:
The example above uses a delay demonstrating that the solution will wait for all completions when there is no success, whereas this example on ideone will demonstrate how a later success will turn the result into success. Note that due to Ideones caching of results you might not notice the delay.
Note that in the case that all futures fail, there is no guaranty about which of the exceptions will get reported. Since it waits for all completions in the erroneous case, any could make it to the final result.