In our previous article, we explored the world of ListenableFuture
. Now, let's dive deeper into more advanced techniques, specifically focusing on transformations and chaining. Imagine we have a ListenableFuture
obtained from an asynchronous service. Additionally, we have a simple method:
Document parse(String xml) {//...
Instead of working with the String
itself, we need the Document
. One approach would be to resolve the Future
and process the String
. However, a more elegant solution is to apply a transformation once the results are available, making our method behave as if it always returned ListenableFuture
. This is remarkably straightforward:
final ListenableFuture future = //... final ListenableFuture documentFuture = Futures.transform(future, new FunctionString, Document() { @Override public Document apply(String contents) { return parse(contents); }});
Or, for better readability:
final FunctionString, Document parseFun = new FunctionString, Document() { @Override public Document apply(String contents) { return parse(contents); }}; final ListenableFuture future = //... final ListenableFuture documentFuture = Futures.transform(future, parseFun);
While Java syntax may have its limitations, let's focus on what we've achieved. Futures.transform()
doesn't wait for the underlying ListenableFuture
to apply the parse()
transformation. Instead, it registers a callback, ready to be notified whenever the given future completes. This transformation is applied dynamically and transparently for us at the right moment. We still have a Future
, but this time wrapping a Document
.
Now, let's take it a step further. We also have an asynchronous, possibly long-running method that calculates the relevance (whatever that means in this context) of a given Document
:
ListenableFuture calculateRelevance(Document pageContents) {//...
Can we somehow chain it with the ListenableFuture
we already possess? First attempt:
final FunctionDocument, ListenableFuture relevanceFun = new FunctionDocument, ListenableFuture() { @Override public ListenableFuture apply(Document input) { return calculateRelevance(input); }}; final ListenableFuture future = //...final ListenableFuture documentFuture = Futures.transform(future, parseFun);final ListenableFutureListenableFuture relevanceFuture = Futures.transform(documentFuture, relevanceFun);
For more information on enhanced asynchronous programming possibilities, visit this link.