# CompletableFuture class in Java

In 
Published 2022-12-03

Future interface is used to represent the future result of an asynchronous computation. The interface provides the methods to check if the computation is completed or not, to wait for its completion, and to retrieve the result of the computation.

CompletableFuture class is an implementation of Future and CompletionStage interfaces. This feature was introduced in Java 8.

CompletableFuture class is used generally when we need to run a task, and the result of that task be used as an input for the next task.

The usage is not very complicated. Take a look at the following example and read carefully the comment added in the code.

Firstly, we define a consumer, a supplier and a function.

Consumer1.class
package com.exampe.java;

import java.util.StringTokenizer;
import java.util.function.Consumer;

public class Consumer1 implements Consumer<String> {
    public void accept(String strIn) {

        StringTokenizer st = new StringTokenizer(strIn);
        Integer nrWords = st.countTokens();
        System.out.println("From Consumer1 / Words in string = "+nrWords);
    }
}
Supplier1.class
package com.exampe.java;

import java.util.function.Supplier;

public class Supplier1 implements Supplier<String> {

    @Override
    public String get() {
        String returnOfSupplier1 = "String from Suplier 1";
        System.out.println("Return of Supplier 1: "+returnOfSupplier1);
        return returnOfSupplier1;
    }
}
Function1.class
package com.exampe.java;

import java.util.function.Function;

public class Function1 implements Function<String, String> {

    @Override
    public String apply(String strIn) {
        String returnOfFunction1 = strIn.toUpperCase();
        System.out.println("Return of Function1: "+returnOfFunction1);
        return returnOfFunction1;
    }
}

And here we have the main class:

package com.exampe.java;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.concurrent.*;

@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) throws InterruptedException, ExecutionException {

		SpringApplication.run(DemoApplication.class, args);

		System.out.println("--------------------------------------------");

		Runnable runnable1 = () -> {
			{
				System.out.println("Runnable #1 is doing something");
			};
		};

		Supplier1 supplier1 = new Supplier1();
		Function1 f1 = new Function1();
		Consumer1 c1 = new Consumer1();

		CompletableFuture<String> cf1 = CompletableFuture
				// runAsync runs a Runnable. There is no result.
				.runAsync(runnable1)
				// supplyAsync run ASYNC and return an object created by the Supplier supplier1
				.supplyAsync(supplier1)
				// The result from the code above is taken by "f1" and after that a result is returned
				.thenApply(f1)
                // The result of the code above is taken by a consumer and something is done with it.
				.thenAccept(c1)
                 // Run a Runnable after the code above
				.thenRun(runnable1)
				.handle((result, exception) -> {
							if (result != null) {
								System.out.println("Oops! We have an exception - " + exception.getMessage());
								return "Unknown!";
							}
							return "No result";
						});

        String result = cf1.get();
		System.out.println("result="+result);
	}

}

When you run the code you will see:

--------------------------------------------
Runnable #1 is doing something
Return of Supplier 1: String from Suplier 1
Return of Function1: STRING FROM SUPLIER 1
From Consumer1 / Words in string = 4
Runnable #1 is doing something
result=No result

Process finished with exit code 0

When we handle the error, we can use exceptionally(), completeExceptionally() or whenCompleted() methods.

You can also take a look at the following articles: