CompletableFuture in Java

Last Updated : 28 May, 2026

CompletableFuture is used to perform asynchronous and non-blocking tasks efficiently. Introduced in Java 8, it allows tasks to run in separate threads and provides powerful methods to manage, combine, and process results of asynchronous computations.

  • Part of the java.util.concurrent package and implements Future and CompletionStage.
  • Supports chaining multiple asynchronous tasks using methods like thenApply() and thenAccept().
  • Helps improve application performance by executing tasks concurrently without blocking the main thread.

Creating a CompletableFuture

CompletableFuture can be created using the supplyAsync() method, which runs a task asynchronously in a separate thread and returns the result later.

  • supplyAsync() is a static method of the CompletableFuture class.
  • It accepts a Supplier functional interface as an argument.
  • Supplier takes no input and returns a value.
Java
import java.util.concurrent.*;

class GFG {
    public static void main(String[] args) throws Exception
    {
        CompletableFuture<String> greetingFuture
            = CompletableFuture.supplyAsync(() -> {
                  // some async computation
                  return "Hello from CompletableFuture";
              });

        System.out.println(greetingFuture.get());
    }
}

Output:

Hello from CompletableFuture

Explanation: This creates a CompletableFuture that will execute the lambda function passed to supplyAsync in a separate thread. And after the execution, the result lambda function is returned by CompletableFuture Object.

Composing CompletableFuture

It allows multiple asynchronous tasks to be combined and processed together using composition methods. These methods create a new CompletableFuture based on the result of previous tasks.

  • thenApply() is used to transform the result of a task.
  • thenCombine() combines results of two independent CompletableFuture objects.
  • thenCompose() chains dependent asynchronous tasks together.
Java
/*package whatever //do not write package name here */

import java.util.concurrent.*;

class GFG {
    public static void main(String[] args) throws Exception
    {
        CompletableFuture<String> helloFuture
            = CompletableFuture.supplyAsync(() -> "Hello");
        CompletableFuture<String> greetingFuture
            = CompletableFuture.supplyAsync(() -> "World");

        CompletableFuture<String> combinedFuture
            = helloFuture.thenCombine(
                greetingFuture, (m1, m2) -> m1 + " " + m2);

        System.out.println(combinedFuture.get());
    }
}

Output:

Hello World

Explanation: This creates two instances of CompletableFuture that return "hello" and "world". And using thenCombine, the result of both the CompletableFutures are concatenated and returned as a final result.

Handling Multiple CompletableFutures

CompletableFuture provides methods to manage multiple asynchronous tasks running in parallel. It helps coordinate tasks and process results after one or all tasks are completed.

  • allOf() waits for all CompletableFuture tasks to complete.
  • anyOf() completes when any one of the tasks finishes first.
  • Useful for executing multiple independent tasks concurrently.
Java
import java.util.concurrent.*;

class GFG {
    public static void main(String[] args) throws Exception {
        CompletableFuture<Integer> f1 = CompletableFuture.supplyAsync(() -> 10);
        CompletableFuture<Integer> f2 = CompletableFuture.supplyAsync(() -> 20);

        // Running multiple tasks in parallel
        CompletableFuture<Void> allOf = CompletableFuture.allOf(f1, f2);
         // Waits for both futures to complete
        allOf.join(); 

        System.out.println("Future1 Result: " + f1.get());
        System.out.println("Future2 Result: " + f2.get());
    }
}

Output
Future1 Result: 10
Future2 Result: 20

Explanation: This program demonstrates how to execute multiple CompletableFuture tasks in parallel using allOf(). The join() method waits for all tasks to complete before fetching their results using get().

Note: The allOf() method is used to combine the results of multiple CompletableFuture instances.

Handling Exception in CompletableFuture

CompletableFuture provides built-in methods to handle exceptions that occur during asynchronous execution. These methods help manage errors and continue program execution smoothly.

  • exceptionally() is used to return a fallback value when an exception occurs.
  • handle() processes both successful results and exceptions together.
  • Helps improve reliability and error handling in asynchronous tasks.
Java
import java.util.concurrent.*;

class GFG {
    public static void main(String[] args) throws Exception
    {
        CompletableFuture<Integer> resultFuture
          // java.lang.ArithmeticException: / by zero
            = CompletableFuture.supplyAsync(() -> 10 / 0)  
                      .exceptionally(ex -> 0);
      
          // 0 - returned by exceptionally block
        System.out.println(resultFuture.get());
    }
}

Output
0

Explanation: This example demonstrates exception handling in CompletableFuture using exceptionally(). When an error occurs in the async task, it provides a fallback value so the program continues smoothly.

Comment