CompletableFuture in Java

CompletableFuture is a class introduced in Java 8 that extends the capabilities of the traditional Future interface. It is designed to handle asynchronous programming in Java, allowing developers to write non-blocking code that can efficiently manage asynchronous tasks. This class provides a comprehensive API for executing, chaining, and combining asynchronous operations, making it a powerful tool for modern Java development.

Overview

CompletableFuture represents a future result of an asynchronous computation. Unlike the traditional Future interface, which requires manual handling of task execution and result retrieval, CompletableFuture offers a more flexible and powerful API. It supports asynchronous programming similar to futures in other languages like Kotlin and Scala. A CompletableFuture starts in an uncompleted state and can be completed by any thread that holds a reference to it using the complete() method. Once completed, the value becomes visible to all threads that are blocked on a get() call, ensuring consistency across threads.

Key Features

  • Asynchronous Computation: CompletableFuture allows tasks to be executed asynchronously, meaning the main thread is not blocked while waiting for the task to complete.
  • Chaining and Combining: Methods such as thenApply, thenCompose, and thenCombine enable chaining and combining multiple asynchronous operations efficiently.
  • Error Handling: It provides mechanisms to propagate and manage errors that occur during asynchronous task execution.
  • Timeout Management: Java 9 introduced methods like orTimeout and completeOnTimeout to handle asynchronous timeouts.

Creating a CompletableFuture

One of the primary ways to create a CompletableFuture is by using the supplyAsync factory method. This method allows you to create a CompletableFuture that is asynchronously completed with the value obtained by invoking a Supplier. It can also accept an Executor to specify the thread pool for executing the Supplier, providing flexibility in execution.

Example

public Future<Double> getPriceAsync(String product) {
    return CompletableFuture.supplyAsync(() -> calculatePrice(product));
}

In this example, the getPriceAsync method returns a CompletableFuture that will be completed asynchronously with the result of the calculatePrice method.

Pipelining Asynchronous Tasks

Pipelining involves chaining multiple asynchronous operations to execute them efficiently without blocking the main thread. CompletableFuture provides several methods to facilitate this:

  • thenApply: Transforms the result of a CompletableFuture when it completes.
  • thenCompose: Chains another CompletableFuture that depends on the result of the first.
  • thenCombine: Combines two independent CompletableFutures and processes their results together.

Example of Asynchronous Computation

var n = 1000;
var future =
  CompletableFuture.supplyAsync(() -> {
  System.out.println("Starting on: "+ Thread.currentThread().getName());
  return NumberService.findPrime(n);
});
var f2 = future.thenApply(l -> {
  System.out.println("Applying on: "+ Thread.currentThread().getName());
  return l * 2;
});
var f3 = future.thenApplyAsync(l -> {
  System.out.println("Async on: "+ Thread.currentThread().getName());
  return l * 3;
});

try {
  System.out.println("F2: "+ f2.get());
  System.out.println("F3: "+ f3.get());
} catch (InterruptedException | ExecutionException e) {
  e.printStackTrace();
}

In this example, CompletableFuture.supplyAsync() is used to run a computation asynchronously. The thenApply() method applies a function to the result of the computation, while thenApplyAsync() applies another function asynchronously.

CompletableFuture vs. Future

CompletableFuture offers a more flexible and powerful API compared to the traditional Future interface. While Future requires manual handling of task execution and result retrieval, CompletableFuture allows for:

  • Chaining: Using lambda expressions to chain asynchronous tasks.
  • Combining: Efficiently combining results of multiple asynchronous tasks.
  • Error Propagation: Managing errors within asynchronous tasks.

Combining CompletableFutures

CompletableFuture provides methods to combine multiple futures:

  • thenCombine: Used for combining two independent tasks.
  • thenCompose: Used when the result of one task is needed as input for another.

These methods enable efficient parallel execution and result combination, enhancing performance and responsiveness in asynchronous programming.

In summary, CompletableFuture is a versatile tool in Java for managing asynchronous programming, offering advanced features for task execution, error handling, and result combination. For more detailed examples and explanations, you can refer to Modern Java in Action and The Well-Grounded Java Developer, Second Edition.

Book TitleUsage of CompletableFutureTechnical DepthConnections to Other ConceptsExamples UsedPractical Application
Modern Java in Action: Lambdas, streams, reactive and functional programmingDiscusses CompletableFuture as a tool for non-blocking, asynchronous computations, error management, and task chaining. moreProvides a comprehensive API overview, including chaining, combining, and error handling. moreConnects CompletableFuture with concepts like asynchronous computation, error propagation, and task combination. moreIncludes examples like creating a CompletableFuture with supplyAsync and chaining tasks with thenApply. moreFocuses on enhancing performance and responsiveness in asynchronous programming. more
The Well-Grounded Java Developer, Second EditionHighlights CompletableFuture for asynchronous programming, similar to futures in other languages. moreExplores function composition, synchronous and asynchronous execution, and state consistency. moreLinks CompletableFuture with function composition and thread management. moreProvides examples of asynchronous computation and function composition using thenApply and thenCompose. moreDemonstrates practical use cases like finding prime numbers asynchronously. more

FAQ (Frequently asked questions)

What is the initial state of a CompletableFuture?

How can you run a computation asynchronously using CompletableFuture?

What is an example of converting a synchronous method to asynchronous using CompletableFuture?

What is the benefit of using CompletableFuture for querying shop prices?

What is the benefit of combining CompletableFutures?

sitemap

Unable to load book!

The book could not be loaded.

(try again in a couple of minutes)

manning.com homepage
test yourself with a liveTest