CompletableFuture is a powerful class in Java's concurrent package that enables asynchronous programming. Unlike traditional blocking operations, CompletableFuture allows you to start a computation and continue with other work while waiting for the result. It represents a stage of computation that will complete at some point in the future, providing methods to chain dependent operations, handle exceptions, and combine multiple asynchronous tasks efficiently.
To create a CompletableFuture, you have two primary static methods. The supplyAsync method is used for tasks that return a value, taking a Supplier function as parameter. The runAsync method is for tasks that don't return a value, taking a Runnable as parameter. Both methods execute the task asynchronously on the ForkJoinPool's common thread pool, allowing your main thread to continue without blocking. You can also provide a custom Executor as a second parameter if needed.
One of CompletableFuture's most powerful features is the ability to chain operations. The thenApply method transforms the result using a function, returning a new CompletableFuture with the transformed value. The thenAccept method consumes the result without returning a value. The thenRun method executes a Runnable after completion, ignoring the result. The thenCompose method is used for chaining dependent asynchronous operations. Each chaining method returns a new CompletableFuture, allowing you to build complex asynchronous pipelines.
CompletableFuture provides robust exception handling mechanisms. The exceptionally method allows you to provide a recovery value when an exception occurs, while the handle method lets you process both successful results and exceptions. For combining multiple futures, allOf waits for all futures to complete before proceeding, useful when you need all results. The anyOf method completes as soon as any of the input futures completes, perfect for racing scenarios. The thenCombine method combines results from two specific futures using a BiFunction.
To retrieve results from CompletableFuture, you have several options. The get method blocks the current thread and throws checked exceptions, while join blocks but throws unchecked CompletionException. For non-blocking retrieval, use getNow with a default value. Best practices include avoiding blocking operations in the main thread, using custom thread pools for CPU-intensive tasks, properly handling exceptions with exceptionally or handle methods, and chaining operations for better code readability. CompletableFuture provides a powerful foundation for building responsive, non-blocking applications in Java.