spotify/completable-futures

repository·master·Indexed 19 days ago

https://github.com/spotify/completable-futures

A Java 8 utility library that simplifies asynchronous code by providing advanced composition and scheduling capabilities for CompletableFuture. Features include tools for combining lists and maps of futures (allAsList, allAsMap), handling failures (successfulAsList), stream collectors (joinList, joinMap), polling external resources, and methods for unwrapping nested CompletionStages such as dereference and supplyAsyncCompose.

Tokens
2.3K
Snippets
15
Records
15
Agent score
15%

What's inside completable-futures

  1. Install completable-futures via Maven

    master

    To use completable-futures in your Java 8 project, add the following dependency to your pom.xml. The library has no additional dependencies.

    <dependency>
        <groupId>com.spotify</groupId>
        <artifactId>completable-futures</artifactId>
        <version>0.3.1</version>
    </dependency>
  2. Use exceptionallyCompose to return a new CompletionStage

    master

    exceptionallyCompose is similar to CompletableFuture.exceptionally, but it allows you to return a new CompletionStage (e.g., a fallback future) instead of a direct value.

    CompletionStage<String> composed = CompletableFutures.exceptionallyCompose(future, throwable -> completedFuture("fallback"));
  3. Combine a list of uniform futures with allAsList

    master

    Use CompletableFutures.allAsList to join a List of futures of the same type into a single future that completes to a list containing all the values.

    List<CompletableFuture<String>> futures = asList(completedFuture("a"), completedFuture("b"));
    CompletableFuture<List<String>> joined = CompletableFutures.allAsList(futures);
  4. Combine multiple futures of different types with combine

    master

    The combine method allows you to merge multiple futures of different types into a single result using a provided function. It supports combining between 2 and 5 futures directly via overloaded methods.

    CompletableFutures.combine(f1, f2, (a, b) -> a + b);
    CompletableFutures.combine(f1, f2, f3, (a, b, c) -> a + b + c);
    CompletableFutures.combine(f1, f2, f3, f4, (a, b, c, d) -> a + b + c + d);
    CompletableFutures.combine(f1, f2, f3, f4, f5, (a, b, c, d, e) -> a + b + c + d + e);
  5. Combine an arbitrary number of futures using varargs

    master

    To combine more than five futures of different types, use the combine method that accepts a vararg of futures and a function. The function receives a CombinedFutures object, which provides a safe .get(future) method to extract values. This is safer than calling .join() on the input futures directly, as it prevents IllegalArgumentException if a future is not part of the combination.

    CompletionStage<String> f1;
    CompletionStage<String> f2;
    CompletionStage<String> result = combine(combined -> combined.get(f1) + combined.get(f2), f1, f2);
    
    // In a combineFutures form:
    CompletionStage<String> f1;
    CompletionStage<String> f2;
    CompletionStage<String> result = dereference(combine(combined -> completedFuture(combined.get(f1) + combined.get(f2)), f1, f2));
  6. Collect futures into a map using joinMap

    master

    joinMap is a stream collector that applies an asynchronous operation to each element in a stream and associates the result with a key derived from the original element.

    collection.stream()
        .collect(joinMap(this::toKey, this::someAsyncFunc))
        .thenApply(this::consumeMap)
  7. Poll an external resource with poll

    master

    If you are dealing with a long-running external task that only exposes a polling API, you can transform it into a future using CompletableFutures.poll. You provide a Supplier<Optional<T>> for the task, a Duration for the frequency, and an Executor.

    Supplier<Optional<T>> pollingTask = () -> Optional.ofNullable(resource.result());
    Duration frequency = Duration.ofSeconds(2);
    CompletableFuture<T> result = CompletableFutures.poll(pollingTask, frequency, executor);
  8. Collect futures into a list using joinList

    master

    joinList is a stream collector that combines multiple futures into a single list. This is useful when applying an asynchronous operation to a collection of entities.

    collection.stream()
        .map(this::someAsyncFunction)
        .collect(CompletableFutures.joinList())
        .thenApply(this::consumeList)
  9. Use supplyAsyncCompose to unwrap nested stages

    master

    supplyAsyncCompose is like CompletableFuture.supplyAsync, but it automatically unwraps a CompletionStage<CompletionStage<T>> to a plain CompletionStage<T> when the Supplier returns a CompletionStage.

    CompletionStage<String> suppliedStage = completedFuture("hello").thenApply(stage -> stage + "-chained");
    CompletionStage<String> outputStage = CompletableFutures.supplyAsyncCompose(suppliedStage);
  10. Combine multiple futures into another future with combineFutures

    master

    Use combineFutures to combine multiple futures into a new future (e.g., when the combining function itself returns a CompletableFuture).

    CompletableFutures.combineFutures(f1, f2, (a, b) -> completedFuture(a + b));
    CompletableFutures.combineFutures(f1, f2, f3, (a, b, c) -> completedFuture(a + b + c));
    CompletableFutures.combineFutures(f1, f2, f3, f4, (a, b, c, d) -> completedFuture(a + b + c + d));
    CompletableFutures.combineFutures(f1, f2, f3, f4, f5, (a, b, c, d, e) -> completedFuture(a + b + c + d + e));
  11. Unwrap nested CompletionStages with dereference

    master

    dereference unwraps a CompletionStage<CompletionStage<T>> into a plain CompletionStage<T>.

    CompletionStage<CompletionStage<String>> wrapped = completedFuture(completedFuture("hello"));
    CompletionStage<String> unwrapped = CompletableFutures.dereference(wrapped);