If your Future
is the result of a call to an ExecutorService
method (e.g. submit()
), the easiest would be to use the CompletableFuture.runAsync(Runnable, Executor)
method instead.
From
Runnbale myTask = ... ;
Future<?> future = myExecutor.submit(myTask);
to
Runnbale myTask = ... ;
CompletableFuture<?> future = CompletableFuture.runAsync(myTask, myExecutor);
The CompletableFuture
is then created "natively".
EDIT: Pursuing comments by @SamMefford corrected by @MartinAndersson, if you want to pass a Callable
, you need to call supplyAsync()
, converting the Callable<T>
into a Supplier<T>
, e.g. with:
CompletableFuture.supplyAsync(() -> {
try { return myCallable.call(); }
catch (Exception ex) { throw new CompletionException(ex); } // Or return default value
}, myExecutor);
Because T Callable.call() throws Exception;
throws an exception and T Supplier.get();
doesn't, you have to catch the exception so prototypes are compatible.
A note on exception handling
The get()
method doesn't specify a throws
, which means it should not throw a checked exception. However, unchecked exception can be used. The code in CompletableFuture
shows that CompletionException
is used and is unchecked (i.e. is a RuntimeException
), hence the catch/throw wrapping any exception into a CompletionException
.
Also, as @WeGa indicated, you can use the handle()
method to deal with exceptions potentially being thrown by the result:
CompletableFuture<T> future = CompletableFuture.supplyAsync(...);
future.handle((ex,res) -> {
if (ex != null) {
// An exception occurred ...
} else {
// No exception was thrown, 'res' is valid and can be handled here
}
});