# The ultimate guide to Futures in Java and Guava

In Java 8 [`CompletableFuture`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) was introduced to finally bring a better way to work with asynchronous logic into Java. Meanwhile Guava has created its own solutions for this problem.

Now, which one should you use?

First let me start by pointing out that Guava has many classes that interact with futures and are meant to be used along-side each other. So most of those classes don’t necessarily step on each others toes.

But first, let’s look at the vanilla Java implementations:

*Title photo by [Drew Graham](https://unsplash.com/@dizzyd718?utm_source=medium&utm_medium=referral) on [Unsplash](https://unsplash.com?utm_source=medium&utm_medium=referral)*

## Future

[`Future`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html) is the base interface and is used by Java’s own `CompletableFuture` and most of the interfaces and classes of Guava. It’s been around since Java 5.

The interface is very rudimentary, only offering methods to check its status, cancel it or gett the result in a blocking way (optionally with timeout). This works for the simplest cases, but if you want to work with multiple `Future`s at once or maybe even chain operations, this interface alone quickly becomes tedious.

Some example code taken from the java documentation:

```
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

In Java 8 [`CompletableFuture`](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html) and its interface `CompletableTask` were added to allow more powerful operations with futures. Those two are so tightly coupled that the interface can essentially be ignored.

`CompletableFuture` implements `Future` and also offers some more methods to work with the result:

* `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.

It also offers you some convenience methods to create `CompletableFutures`:

* `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.

Some example code:

```
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`

While the fluent style of `CompletableFuture` is certainly a great improvement to the bare-bones approach of `Future`, it still has its quirks.

For one it’s easy to forget that it can also be canceled. This means that if you return a `CompletableFuture` **the caller can cancel it! **This might leave you with resources not being properly closed or an unexpected state. The easiest way to avoid this is to wrap your `CompletableFuture` in another one.

Another problem is also that exceptions are handled slightly inconsistently, which the documentation doesn’t mention:

```
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;
    });
```


Lastly, handling only specific exceptions isn’t that easy. The function in `exceptionally` receives an instance of `Throwable`, which is a checked exception. This means you can’t re-throw it without first wrapping it in a `RuntimeException`, preferably a `CompletionException`.

While a `CompletionException` thrown in one of those methods is directly returned (for instance when using `join`), nested ones are not unwrapped. This means that you’ll likely end up with some boilerplate code like this:

```
.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

Moving away from the Java standard library, Guava’s static class [`Futures`](https://guava.dev/releases/snapshot/api/docs/com/google/common/util/concurrent/Futures.html) contains methods to more effectively work with Futures. It does so mostly by utilizing the `ListenableFuture` interface that we’ll look at next.

Notably, however, it also has a `transform` method that allows you to create a new future based on another one and a function. The new future will complete with the result of the provided one being transformed by the given function. This essentially mimics the way that `CompletableFuture.thenApply` works.

This class should be your first stop when trying to work with futures and Guava!

## ListenableFuture

[`ListenableFuture`](https://guava.dev/releases/snapshot/api/docs/com/google/common/util/concurrent/ListenableFuture.html) is a simple interface in Guava that implements `Future` and only adds one method: `addListener`.

This method allows you to register listeners that are called once the future completes. Albeit they do not directly get the result, you may get it using the `get` method of the `ListenableFuture` itself.

This interface is the main one utilized in the `Futures` class. It is also implemented by most of Guava’s future classes.

### ListenableFutureTask

[This class](https://guava.dev/releases/snapshot/api/docs/com/google/common/util/concurrent/ListenableFutureTask.html) is essentially a bare-bones implementation of the `ListenableFuture` interface. It has two factory methods using `Callable` or `Runnable` but otherwise only implements the methods of its interface.

### SettableFuture

[`SettableFuture`](https://guava.dev/releases/snapshot/api/docs/com/google/common/util/concurrent/SettableFuture.html) extends the methods of the `ListenableFuture` interface with setter methods. You can set its success value, exception or even set it based on another future.

This class is mainly useful for when you already have a thread on which you want to complete your future.

### AbstractFuture

As the name implies [`AbstractFuture`](https://guava.dev/releases/snapshot/api/docs/com/google/common/util/concurrent/AbstractFuture.html) is an abstract implementation of the `ListenableFuture` interface. Beyond the already mentioned `addListener` and setters, it also has some methods that expose its internal state.

It’s unlikely that you’ll need this class, but it can be used to implement your own versions of `ListenableFuture`.

## FluentFuture

`FluentFuture` is the most similar to Java’s `CompletableFuture`. It implements `ListenableFuture` and also offers mapping methods in `transform` and `catching`.

In this case `catching` allows catching specific exceptions, not just a `Throwable`. This enables a more selective approach to exception handling where the theoretical possibility of checked exceptions doesn’t result in a lot of boilerplate code.

Some example code taken from its documentation:

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


## ClosingFuture

[`ClosingFuture`](https://guava.dev/releases/snapshot/api/docs/com/google/common/util/concurrent/ClosingFuture.html) is similar to `FluentFuture`, but acts more as a builder than a future itself. It offers methods to transform values, catch exceptions and combining multiple of them. At the end a `ClosingFuture` always has to be “finished”.

There is currently two ways you can finish it:

* `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.

An example from its documentation:

```java
FluentFuture<UserName> userName =
     ClosingFuture.submit(
             closer -> closer.eventuallyClose(database.newTransaction(), closingExecutor),
             executor)
         .transformAsync((closer, transaction) -> transaction.queryClosingFuture("..."), executor)
         .transform((closer, result) -> result.get("userName"), directExecutor())
         .catching(DBException.class, e -> "no user", directExecutor())
         .finishToFuture();
```

## Conclusion

When working with vanilla Java, your best bet is `CompletableFuture`. Once you also have Guava, you have a myriad of options to choose from. All of them fill slightly different niches and are meant for different levels of detail.

In the end, Guava’s many classes can quickly become overwhelming and confusing.

Personally, I’ll probably try out `ClosingFuture` and `FluentFuture` a bit more, but stick with `CompletableFuture` for now — mainly because I can safely stick it in APIs without having to worry about introducing a new dependency.
