CodeX
Published in

CodeX

The ultimate guide to Futures in Java and Guava

Untangling the mess of Futures

Photo by Drew Graham on Unsplash

Future

interface ArchiveSearcher { String search(String target); }
class App {
ExecutorService executor = ...
ArchiveSearcher searcher = ...
void showSearch(final String) throws InterruptedException { Future<String> future
= executor.submit(new Callable<String>() {
public String call() {
return searcher.search(target);
}});
displayOtherThings(); // do other things while searching try {
displayText(future.get()); // use future
} catch (ExecutionException ex) { cleanup(); return; }
}
}

CompletableFuture

  • thenAccept allows you to register a function that will be called upon completion and whose result will be used for a new CompletableFuture that is returned from this method.
  • exceptionally does the same as thenAccept, except that it is called when the CompletableFuture is completed exceptionally.
  • handle allows you to handle both the success value as well as the exception in the same function.
  • join will block until the CompletableFuture completes and either return the value or throw any of the occurring exceptions.
  • supplyAsync let’s you specify a Supplier that will be called asynchronously and whose result will be the result of the CompletableFuture once finished.
  • completedFuture will immediately return a successfully completed future. It’s counterpart failedFuture was added in Java 9.
public CompletableFuture<List<User>> loadActiveUsers() {    return httpClient.<List<User>>sendAsync(request, bodyHandler)
.thenApply(this::filterListOfUsersForActiveOnes)
.exceptionally(throwable -> {
LOG.warn(throwable);
return List.of();
});
}
public void displayListOfActiveUsers() { try {
CompletableFuture<> activeUsersFuture = loadActiveUsers();
displayOtherStuff();

try {
displayActiveUsers(activeUsersFuture.join());
} catch (CompletionException e) {
LOG.error(e);

displayNoUsers();
}
}
}

Problems with CompletableFuture

NullPointerException exception = new NullPointerException(":(");CompletableFuture.failedFuture(exception)
.exceptionally(throwable -> {
// here throwable is the exception from above
return null;
});
CompletableFuture.failedFuture(exception)
.thenApply(Object::toString)
.exceptionally(throwable -> {
// here throwable is a CompletionException that wraps the
// exception from above
return null;
});
.exceptionally(throwable -> {
while (throwable instanceof CompletionException) {
throwable = throwable.getCause();
}
if (throwable instanceof NullPointerException) {
// handle the exception I care about
return null;
} else {
throw new CompletionException(throwable);
}
})

Futures

ListenableFuture

ListenableFutureTask

SettableFuture

AbstractFuture

FluentFuture

ListenableFuture<Boolean> adminIsLoggedIn =
FluentFuture.from(usersDatabase.getAdminUser())
.transform(User::getId, directExecutor())
.transform(ActivityService::isLoggedIn, threadPool)
.catching(RpcException.class, e -> false, directExecutor());

ClosingFuture

  • finishToFuture will return a FluentFuture that will complete once all of the steps defined by the ClosingFuture are completed.
  • finishToValueAndCloser will call a callback once finished.
Example code using ClosingFuture taken from it’s documentation

Conclusion

--

--

Everything connected with Tech & Code. Follow to join our 1M+ monthly readers

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Oscar Ablinger

Hi, I’m a Software Engineer that just writes on here about whatever he finds out in a given week. Could be scripts, insights or explanations of things I learned