Java concurrency
CompletableFuture
Future
RxJava
Observable

Difference between CompletableFuture, Future and RxJava's Observable

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In the world of Java, asynchronous programming has become an essential part of many applications to handle operations that could otherwise block the main thread. Among the popular tools provided for handling asynchronous tasks in Java are CompletableFuture, Future, and RxJava's Observable. Each of these has unique features, strengths, and weaknesses that make them suitable for different scenarios. This article delves into their differences, providing technical insights and examples to help you choose the right tool for your needs.

Future

Future is a part of the Java concurrency framework introduced in Java 5, found in the java.util.concurrent package. It represents a promise to produce a result asynchronously. However, Future has several limitations:

  1. Blocking Operations: To retrieve the result, you typically call get(), which is a blocking operation. This can be problematic if the computation is lengthy.
  2. No Exception Handling: Future does not have built-in support for handling exceptions that may occur during asynchronous execution.
  3. Manual Cancellation: Cancelling a task requires explicit calls.

Example:

java
1ExecutorService executorService = Executors.newSingleThreadExecutor();
2Future<Integer> future = executorService.submit(() -> {
3    // Simulate long-running task
4    Thread.sleep(1000);
5    return 42;
6});
7
8try {
9    Integer result = future.get(); // Blocks until the task is completed.
10} catch (InterruptedException | ExecutionException e) {
11    e.printStackTrace();
12}

CompletableFuture

CompletableFuture, introduced in Java 8, is a significant improvement over Future. It's a flexible and feature-rich API that supports non-blocking operations and can be used to design multi-stage asynchronous pipelines.

  1. Non-blocking: It allows chaining of computations without having to block the thread.
  2. Combining Futures: You can combine multiple CompletableFutures to create a complex async pipeline using methods like thenCombine, thenCompose, and more.
  3. Exception Handling: Provides methods to handle exceptions more succinctly.

Example:

java
1CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
2    // Simulate long-running task
3    try { Thread.sleep(1000); } catch (InterruptedException e) { }
4    return 42;
5});
6
7future.thenApply(result -> result * 2)
8      .exceptionally(ex -> {
9          System.out.println("Exception: " + ex);
10          return null;
11      })
12      .thenAccept(result -> System.out.println("Result: " + result));

RxJava's Observable

RxJava is a library implementing the ReactiveX API, providing a robust framework for reactive programming. Observable is one of its core components designed for handling sequences of asynchronous events.

  1. Reactive Streams: Observable emits items over time and can represent an arbitrary number of values, unlike Future or CompletableFuture.
  2. Operators Galore: Supports extensive operators for transforming, combining, and filtering data streams.
  3. Backpressure Handling: Manages the flow of data in case of a slower consumer processing rate.

Example:

java
1Observable<Integer> observable = Observable.create(emitter -> {
2    try {
3        emitter.onNext(42);    // Emit items
4        emitter.onComplete();  // Signal completion
5    } catch (Exception e) {
6        emitter.onError(e);
7    }
8});
9
10observable.subscribe(
11    result -> System.out.println("Received: " + result),
12    throwable -> System.out.println("Error: " + throwable),
13    () -> System.out.println("Completed")
14);

Feature Comparison

Here is a comparison of the key features of Future, CompletableFuture, and RxJava's Observable:

FeatureFutureCompletableFutureRxJava Observable
BlockingYesOptional (supports non-blocking)No
Multi-stageNoYesYes
Exception HandlingNo (manual)YesYes
CancellationYes (manual)YesYes
Backpressure HandlingNoNoYes
Stream ProcessingNo (single result)YesYes

Conclusion

While Future was a good start for asynchronous programming in Java, its limitations have been well addressed by CompletableFuture and RxJava's Observable. CompletableFuture is more suited for non-blocking, potential one-off tasks with straightforward exception handling, whereas Observable shines in situations where you deal with a stream of data, offering a vast array of operators for sophisticated stream manipulation. Choosing the right tool depends largely on the specific requirements of your application and the nature of the tasks you are dealing with.


Course illustration
Course illustration

All Rights Reserved.