Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Playing with Java 8’s Completable Futures

DZone's Guide to

Playing with Java 8’s Completable Futures

CompletableFutures are similar to Guava’s ListenableFutures, which allow you to add a completion listener to a regular Java future, but CompletableFutures have a bit more functionality.

· Java Zone
Free Resource

Bitbucket is for the code that takes us to Mars, decodes the human genome, or drives your next car. What will your code do? Get started with Bitbucket today, it's free.

Of the many additions to Java 8 such as the Stream API and lambdas, I noticed one of the lesser talked about features was CompletableFutures. So I decided to play around with them on the last Java component I wrote. My use case, in a nutshell, was piping large volumes of data from a distributed file system, compressing it, and uploading to individual destinations on Amazon S3. playing-with-java8

For anyone who has worked with Guava’s ListenableFutures, which allow you to add a completion listener to a regular Java future, CompletableFutures are along the same line as these with a bit more functionality — such as easily composing multiple stages of future work for a single computation. To create a basic CompletableFuture is as simple as creating an existing Future, the following example shows the creation and retrieval of a computation:

CompletableFuture futureCount = CompletableFuture.supplyAsync(
    () -> {
        try {
            // Simulate long running task
            Thread.sleep(5000);
        } catch (InterruptedException e) { }
        return 10;
    });
// Do some other work in the meantime

CompletableFuture.supplyAsync allows you to run a task asynchronously on Java’s ForkJoinPool and also has the option to supply your own Executor if you want more control on the ThreadPool. Now lets get the result of the above computation.

try {
    int count = futureCount.get();
    System.out.println(count);
} catch (InterruptedException | ExecutionException ex) {
    // Exceptions that occur in future will be thrown here.
}

As with regular Java Future’s, any exceptions that occur during computation will be thrown when .get() is called. Now lets look at composing multiple stages of work to a CompletableFuture. I’m going to use RxJava to to populate my mock external data source, if you’re unfamiliar with Observables, they simply provide a stream of objects which are pushed to subscribers asynchronously. They work quite nicely with CompletableFutures.

public CompletableFuture countEvents() {
    CompletableFuture result = new CompletableFuture<>();
    AtomicInteger count = new AtomicInteger();
    Observable.just("1", "2", "3", "err", "4").subscribe(ev -> {
            try {
                int x = Integer.parseInt(ev);
                count.set(count.get() + x);
            } catch (NumberFormatException e) { }
        },
        throwable -> result.complete(0);
        () -> {
            try {
                //simulate io delay
                Thread.sleep(3000);
            } catch (InterruptedException e) { }
            result.complete(count.get());
        }
    );
    return result;
}

This code is the same as before, but I’m showing the example external data streaming asynchronously and used it to create the result of the CompletableFuture. Next we’ll set up some additional stages of work to perform on the result before calling .get() on the future.

CompletableFuture data = countEvents()
    .thenApply(count -> {
        int transformedValue = count * 25;
        return transformedValue;
    }).thenApply(transformed -> "data-" + transformed);

try {
    System.out.println(data.get());
} catch (InterruptedException | ExecutionException e) {
    e.printStaceTrace();
}

This basic example shows how you can very easily transform and manipulate your data through several stages using CompletableFuture’s. In the above example, the final value printed would be data-250. I hope you found this helpful as a quick introduction into CompletableFuture’s. They are worth playing around with if you are interested in writing code with a more functional approach. There is plenty more functionality to be taken advantage of which we will cover in a future blog post. Stay tuned!

Bitbucket is the Git solution for professional teams who code with a purpose, not just as a hobby. Get started today, it's free.

Topics:
java ,java 8 ,rxjava ,functional programming

Published at DZone with permission of Mitchell Mcnary. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}