Unlock 2x Faster Async Programming with Java Futures

Last time, we delved into the realm of ListenableFuture. I promised to unveil more sophisticated techniques, specifically transformations and chaining. Let’s embark on a straightforward journey. Suppose we possess a ListenableFuture obtained from some asynchronous service. Additionally,

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.


Liam Wilson

17 Blog posts

Comments