Tech Master Tutorials
Email Facebook Google LinkedIn Pinterest Twitter
Home Java Java 8 Java Interview Questions Java8 Interview Questions Object Oriented Programming in Java JVM Java Programming

CompletableFuture - Java Async Programming

Prior to understanding execution of completion stages, good to have knowledge on the below
Methods used in the below examples of serial execution of the completablefutures:
  • thenCompose () : Supplies the result of the completion stage as input and returns a new CompletionStage that holds the result of the computation passed inside the function.
  • completedFuture(): Returns a completed CompletableFuture wrapped with the passed value to the method.



Executing Completable Futures in serial : Execute all CompletableFuture in Serial

package completables;

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

public class CompletableFuturesSerialExecution_All {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		CompletableFuturesSerialExecution_All completableFuturesSerialExecution
												 = new CompletableFuturesSerialExecution_All();
		completableFuturesSerialExecution.executeCompletableFuturesSerially();
	}

	private void executeCompletableFuturesSerially() throws InterruptedException, ExecutionException {
		TaskImpl customRuleNumber = new TaskImpl();
		for (int i = 0; i < 5; i++) {
			CompletableFuture<String> completableFuture = CompletableFuture.completedFuture(null);
			completableFuture = executeRule(completableFuture, i, customRuleNumber);
		}
	}

	private CompletableFuture<String> executeRule(CompletableFuture<String> completableFuture,
													 int i, TaskImpl customRuleNumber)
	 												 throws InterruptedException, ExecutionException {
		return completableFuture.thenCompose(__ -> customRuleNumber.executeRule(i));
	}

	abstract class Task {
		abstract CompletionStage<String> executeRule(int n);
	}

	class TaskImpl extends Task {
		CompletableFuture<String> executeRule(int n) {
			System.out.println("Executing Task number = " + n);
			return CompletableFuture.completedFuture("" + n);
		};
	}

}


Execution Output:

Executing Task number = 0
Executing Task number = 1
Executing Task number = 2
Executing Task number = 3
Executing Task number = 4

Here in the above example, we are executing multiple tasks in the completable futures in
serial order.


Executing Completable Futures in serial : return after one of the futures return the response

package completables;

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

public class CompletableFutureSerial_breakAfterResult {

	public static void main(String[] args) throws InterruptedException, ExecutionException {
		CompletableFutureSerial_breakAfterResult completableFuturesSerialExecution
													 = new CompletableFutureSerial_breakAfterResult();
		completableFuturesSerialExecution.executeCompletableFuturesSerially();
	}

	private void executeCompletableFuturesSerially() throws InterruptedException, ExecutionException {
		TaskImpl customRuleNumber = new TaskImpl();
		for (int i = 0; i < 5; i++) {
			CompletableFuture<String> completableFuture = CompletableFuture.completedFuture(null);
			completableFuture = executeRule(completableFuture, i, customRuleNumber);
			if (completableFuture.get() != null) {
				System.out.println("Task executed and returned non-null result : Task Number = "
				 + completableFuture.get());
				break;
			}
		}
	}

	private CompletableFuture<String> executeRule(CompletableFuture<String> completableFuture,
													 int i, TaskImpl customRuleNumber)
	 												throws InterruptedException, ExecutionException {
		return completableFuture.thenCompose(__ -> customRuleNumber.executeRule(i));
	}

	abstract class Task {
		abstract CompletionStage<String> executeRule(int n);
	}

	class TaskImpl extends Task {
		CompletableFuture<String> executeRule(int n) {
			if (n == 1) {
				System.out.println("Executing Task number = " + n);
				return CompletableFuture.completedFuture("" + n);
			}
			System.out.println("returns null");
			return CompletableFuture.completedFuture(null);
		};
	}

} 


Output:
returns null
Executing Task number = 1
Task executed and returned non-null result : Task Number = 1

Here in the above example Tas- 0 returns null , then execution continues and when task-1 return the
non-null object then we stop the execution as we have got our result.
We can put a different condition according to our use case and break whenever we want to get out of
the serial execution.