References
Baeldung: Guava’s Futures and ListenableFuture
Since we’re working with this type of Future, we want to convert other types into ListenableFuture’s.
From CompletableFuture
import net.javacrumbs.futureconverter.java8guava.FutureConverter
CompletableFuture<String> myCompletableFuture = ...
ListenableFuture<String> myListenableFuture =
FutureConverter.toListenableFuture(myCompletableFuture);
To convert a result to a ListenableFuture
Similar to CompletableFuture.completedFuture("Hello World")
ListenableFuture<String> myFutureString =
Futures.immediateFuture("hello world");
To convert a List of ListenableFuture’s to a ListenableFuture of List
(Similar to CompletableFuture.allOf(myListOfFutures.toArray(new CompletableFuture<?>[0]))
)
List<ListenableFuture<String>> myListOfFutures = ...
ListenableFuture<List<String>> myFutureOfList =
Futures.allAsList(myListOfFutures);
To transform results of a ListenableFuture
(Similar to CompletableFuture.thenApply)
public Lion makeFierce(Cat cat) {...}
ListenableFuture<Cat> aCatFuture = ...
ListenableFuture<Lion> = Futures.transform(
aCatFuture,
(aCat) -> makeFierce(aCat),
executor);
When the transform is another async process, then use .transformAsync()
(Similar to CompletableFuture.thenCompose)
public ListenableFuture<Cat> grow(Kitten kitten) {...}
ListenableFuture<Kitten> aKittenFuture = ...
ListenableFuture<Cat> = Futures.transformAsync(
aKittenFuture,
(aCat) -> grow(aCat),
executor);
What if you have futures you had to run one after another? For example, you’re fetching from a service that returns pages of info, and you don’t know how many pages there are.
int max_pages_per_fetch = 10;
int page = 1;
ListenableFuture<List<Page>> bookpages =
recursivelyFetchAllPages(page);
public ListenableFuture<List<Page>> recursivelyFetchAllPages(int page) {
ListenableFuture<PageSet> pageSetFuture =
bookService.fetchPage(page, max_pages_per_fetch);
return Futures.transformAsync(
pageSetFuture,
pageSet -> {
List<Page> mutablePages = new LinkedList(pageSet.getPages());
if (pageSet.hasMorePages()) {
ListenableFuture<List<Page>> remainingPagesFuture =
recursivelyFetchAllPages(page+1);
return Futures.transform(
remainingPagesFuture,
remainingPages -> {
mutablePages.addAll(remainingPages);
return mutablePages;
},
executor());
},
executor());
}
Waiting on several different Futures to complete and combining their result
(Similar to CompletableFuture.allOf)
ListenableFuture<Cat> catFuture = ...
ListenableFuture<Dog> dogFuture = ...
ListenableFuture<PetBasket> basketFuture =
Futures.whenAllSucceed(catFuture, dogFuture)
.call(() -> {
Cat cat = Futures.getDone(catFuture);
Dog dog = Futures.getDone(dogFuture);
PetBasket basket = new PetBasket();
basket.add(cat);
basket.add(dog);
return basket;
}, executor);