Java CompletableFuture thenApply() Method

The CompletableFuture class in Java provides the thenApply() method to transform the result of a CompletableFuture when it completes.

Introduction

The CompletableFuture.thenApply() method is used to process and transform the result of a CompletableFuture once it completes. It takes a function that processes the result and returns a new CompletableFuture with the transformed result.

thenApply Method Syntax

The syntax for the thenApply method is as follows:

public <U> CompletableFuture<U> thenApply(Function<? super T, ? extends U> fn)
  • The method takes a single parameter fn of type Function<? super T, ? extends U>, which represents the function to apply to the result.
  • The method returns a new CompletableFuture<U> that holds the transformed result.

Examples

Example 1: Transforming a String Result

In a scenario where you have a CompletableFuture that completes with a string, you might want to transform the result to uppercase.

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class ThenApplyExample {
    public static void main(String[] args) {
        // Create a CompletableFuture that completes with a string
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello");

        // Transform the result to uppercase using thenApply
        CompletableFuture<String> transformedFuture = future.thenApply(String::toUpperCase);

        // Process the transformed result
        transformedFuture.thenAccept(result -> System.out.println("Transformed result: " + result));

        // Wait for the future to complete
        try {
            transformedFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

Output:

Transformed result: HELLO

Example 2: Task Management System

In a task management system, you might want to transform the result of a task to include additional information such as the completion time.

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.time.LocalDateTime;

public class TaskManagementSystem {
    public static void main(String[] args) {
        // Create a CompletableFuture that completes with a task
        CompletableFuture<Task> taskFuture = CompletableFuture.supplyAsync(() -> new Task("Complete project report", 2));

        // Transform the result to include completion time using thenApply
        CompletableFuture<TaskResult> resultFuture = taskFuture.thenApply(task ->
            new TaskResult(task, LocalDateTime.now())
        );

        // Process the transformed result
        resultFuture.thenAccept(result -> System.out.println("Task result: " + result));

        // Wait for the future to complete
        try {
            resultFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

class Task {
    private String description;
    private int priority;

    public Task(String description, int priority) {
        this.description = description;
        this.priority = priority;
    }

    @Override
    public String toString() {
        return description + " (Priority: " + priority + ")";
    }
}

class TaskResult {
    private Task task;
    private LocalDateTime completionTime;

    public TaskResult(Task task, LocalDateTime completionTime) {
        this.task = task;
        this.completionTime = completionTime;
    }

    @Override
    public String toString() {
        return task + ", Completed at: " + completionTime;
    }
}

Output:

Task result: Complete project report (Priority: 2), Completed at: 2023-07-10T14:38:42.551

Example 3: Calculating a Result Based on Initial Input

In a scientific calculation scenario, you might want to transform the result of a calculation to another form, such as converting from radians to degrees.

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CalculationExample {
    public static void main(String[] args) {
        // Create a CompletableFuture that completes with a calculation result in radians
        CompletableFuture<Double> calculationFuture = CompletableFuture.supplyAsync(() -> Math.PI);

        // Transform the result to degrees using thenApply
        CompletableFuture<Double> degreesFuture = calculationFuture.thenApply(radians -> Math.toDegrees(radians));

        // Process the transformed result
        degreesFuture.thenAccept(result -> System.out.println("Result in degrees: " + result));

        // Wait for the future to complete
        try {
            degreesFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
}

Output:

Result in degrees: 180.0

Conclusion

The CompletableFuture.thenApply() method in Java is used for transforming the result of a CompletableFuture once it completes. It is particularly useful in scenarios where you need to process the result of an asynchronous computation, such as transforming strings, adding additional information to task results, or performing further calculations based on initial results.

Comments