Part 1 - CompletableFuture (Short)
Part 1 - CompletableFuture (Short)
CompletableFuture
Outline
Executors and Future
Creating CompletableFuture
Usage Patterns
Executor and Future
Latency Problem
latency
com.iteratrlearning.examples.promises.pricefinder.PriceCatalogueExample
Blocking
Product product = catalogue.productByName(productName);
double exchangeRate
= exchangeService.lookupExchangeRate(USD, localCurrency);
Catalogue PriceFinder
Calculate
ExchangeService
latency
Solutions
1. Thread based approach (1995+)
3. CompletableFuture (2014+)
Threads
● You can run two or more tasks concurrently by running multiple threads
t.start();
com.iteratrlearning.examples.promises.pricefinder.PriceCatalogueThread
ExecutorService
...
2. Execute task
1. Submit task
Thread
3. Complete task pool
Executor
Service Working thread
Idle thread
ExecutorService
● Decouples Task Submission from Execution
}
A Future is an I-owe-you for a value
Using ExecutorService
ExecutorService executorService
= Executors.newFixedThreadPool(10);
Future<Price> futurePrice
= Executors.newFixedThreadPool(10);
Future<Price> futurePrice
com.iteratrlearning.problems.promises.pricefinder.PriceCatalogueFuture
Problems with Future
● How to find the first result of two futures?
● Akka
Creating CompletableFuture
Creation patterns
// 1. Instantiate the future
CompletableFuture<Price> price =
○ Uncompleted
○ Completed exceptionally
Completing a CompletableFuture
future.complete(42);
future.completeExceptionally(new TimeoutException());
Future, Promise, Deferred
Future vs Promise
● Future lets you read a value at some point in time
com.iteratrlearning.problems.promises.pricefinder.PriceCatalogueCFSimple
Usage Patterns
Diagram annotations
A -> B: Function<A, B>
A -> B
A B
thenApply
CompletableFuture<A> CompletableFuture<B>
Transforming CompletableFuture
CompletableFuture<Integer> plusOne
A -> B
A B
thenCompose
CompletableFuture<A> CompletableFuture<B>
Composing CompletableFutures
// Composing maps a value into a CompletableFuture (dual of flatMap)
A
(A, B) -> C
C
thenCombine
B
Combining two independent CompletableFutures
CompletableFuture<User> futureUser = …;
CompletableFuture<List<Course>> futureCourses = …;
CompletableFuture<LearningPlan> futureLearningPlan
thenCompose
Fork/Join Pool (methods with async suffix)
Thread a thread from
Fork/Join pool
thenComposeAsync
ExecutorService
Thread New thread from
ExecutorService’s thread pool
thenComposeAsync(completableFuture,
executorService)
Refactoring exercise
Refactor to make use of idiomatic CompletableFuture operations.
com.iteratrlearning.problems.promises.pricefinder.PriceCatalogueCFIdiomatic
thenCompose
Catalogue PriceFinder
thenAccept
thenCombine Calculate
ExchangeService
Summary
CompletableFuture Pros
● Async API for combining services
● Bloated API
com.iteratrlearning.examples.promises.patterns.CFExecution
Dealing with Exceptions
Exceptions
● When a CompletableFuture completes with Exception then the
downstream CompletionStage is in exception state
priceFuture.exceptionally(ex -> {
// recovery mechanism
// return value
if(ex == null) {
// value state
} else {
// exception state
});
Refactoring exercise
Should print result or “Sorry try again next time: Couldn't connect to the Exchange sorry!”
thenCompose
Catalogue PriceFinder
Calculate
thenCombine
AsyncExchangeService
Sequence Patterns
anyOf
B ? Object
First to complete
C
Anyof
Scenario: query two (or more) services and return the first to complete
CompletableFuture.anyOf(
B Void
All completed
C
allOf
● Returns a completed CompletableFuture when all CompletableFutures
are completed
A A
A A
A A
List<CompletableFuture<A>> CompletableFuture<List<A>>
List<CompletableFuture<T>>
// If any of the of the futures complete exceptionally or are cancelled then the result does
CompletableFuture<Void> allFuturesDone =
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
futures.stream()
.map(CompletableFuture::join)
.collect(toList()));
}
Refactoring Exercise
Calculate the total price for a list of products
com.iteratrlearning.problems.promises.pricefinder.PriceCatalogueAll
Final Practical (Optional)
com.iteratrlearning.problems.promises.wrapup.BetfairWrapUp
Implementing non-blocking Timeout
public <T> CompletableFuture<T> timeoutAfter(long timeout, TimeUnit unit) {
delayer.schedule(() ->
return result;