Language
日本語
English

Caution

JavaScript is disabled in your browser.
This site uses JavaScript for features such as search.
For the best experience, please enable JavaScript before browsing this site.

Java Dictionary

  1. Home
  2. Java Dictionary
  3. CompletableFuture.supplyAsync() / thenApply() / join()

CompletableFuture.supplyAsync() / thenApply() / join()

A mechanism for writing asynchronous processing in a declarative style (Java 8 and later). You can chain and combine multiple asynchronous tasks, and write error handling as part of a single fluent chain.

Syntax

import java.util.concurrent.*;

// Runs a task asynchronously and returns a result (Supplier).
CompletableFuture<T> cf = CompletableFuture.supplyAsync(() -> /* expression returning type T */);

// Runs a task asynchronously with no return value (Runnable).
CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> { /* task */ });

// Transforms the result and passes it to the next stage (takes a Function).
cf.thenApply(result -> /* transformation */);

// Receives the result and returns a new CompletableFuture.
cf.thenCompose(result -> /* expression returning a CompletableFuture */);

// Consumes the result (no return value).
cf.thenAccept(result -> { /* task */ });

// Returns a default value if an exception occurs.
cf.exceptionally(ex -> /* default value */);

// Handles both the result and any exception.
cf.handle((result, ex) -> /* handler */);

// Blocks until the result is available and retrieves it.
T value = cf.join();
T value = cf.get(); // Throws InterruptedException and ExecutionException.

Main Methods

MethodDescription
supplyAsync(Supplier)Runs a supplier asynchronously and returns a CompletableFuture with a result.
runAsync(Runnable)Runs a Runnable asynchronously. Returns CompletableFuture<Void>.
thenApply(Function)Receives the completed result, transforms it, and passes it to the next stage.
thenAccept(Consumer)Receives the completed result and processes it. Passes Void to the next stage.
thenCompose(Function)Receives the result and returns a new CompletableFuture, flattening the chain.
exceptionally(Function)Returns a default value when an exception occurs.
handle(BiFunction)Handles both the result and any exception. Called in both normal and error cases.
allOf(futures...)Waits until all of the given CompletableFuture instances complete.
anyOf(futures...)Proceeds as soon as any one of the given CompletableFuture instances completes.
join()Returns the result. Unlike get(), it does not throw checked exceptions.

Sample Code

import java.util.concurrent.*;

// Fetch data asynchronously and transform it.
CompletableFuture<String> cf = CompletableFuture
    .supplyAsync(() -> {
        // Simulates a time-consuming operation (e.g., an API call).
        try { Thread.sleep(500); } catch (InterruptedException e) {}
        return "hello";
    })
    .thenApply(String::toUpperCase)    // Transforms to "HELLO".
    .thenApply(s -> s + " WORLD");    // Transforms to "HELLO WORLD".

System.out.println(cf.join()); // Prints "HELLO WORLD".

// Use exceptionally() to return a default value on error.
CompletableFuture<Integer> safeCf = CompletableFuture
    .supplyAsync(() -> {
        if (true) throw new RuntimeException("Processing failed.");
        return 42;
    })
    .exceptionally(ex -> {
        System.out.println("Error: " + ex.getMessage());
        return -1; // Returns a default value.
    });
System.out.println(safeCf.join()); // Prints "-1".

// Use allOf() to wait for multiple asynchronous tasks to complete.
CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(() -> 20);
CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(() -> 30);

CompletableFuture.allOf(task1, task2, task3).join();
int total = task1.join() + task2.join() + task3.join();
System.out.println("Total: " + total); // Prints "Total: 60".

Notes

Using CompletableFuture lets you combine asynchronous tasks sequentially and in parallel without falling into callback hell. Use thenApply() to transform results, thenCompose() to chain asynchronous tasks (flat map), and handle() as a general-purpose handler that runs in both normal and error cases.

By default, tasks run on the shared ForkJoinPool.commonPool(). To use a custom thread pool, pass an Executor as the second argument, for example: supplyAsync(supplier, executor).

For managing thread pools, see ExecutorService / Executors.newFixedThreadPool().

If you find any errors or copyright issues, please .