Java CompletableFuture
Asynchronous programming with composable futures for non-blocking operations
java (8+)
2025-11-03
async
concurrency
futures
java8
Description
CompletableFuture is a powerful class introduced in Java 8 for asynchronous programming. It represents a future result that can be completed asynchronously and provides methods for composing, combining, and handling asynchronous operations.
Key Features
- Asynchronous execution: Run tasks without blocking the main thread
- Composition: Chain multiple async operations together
- Combination: Combine results from multiple futures
- Exception handling: Handle errors in async operations
- Thread pool control: Use custom ExecutorService
Common Patterns
- thenApply: Transform result of one future
- thenCompose: Chain futures sequentially
- thenCombine: Combine two futures
- allOf/anyOf: Wait for multiple futures
- Exception handling: handle, exceptionally, whenComplete
Code
import java.util.concurrent.*;import java.util.function.*;import java.util.stream.Collectors;import java.util.List;public class AsyncUtils { // Simple async execution public static <T> CompletableFuture<T> supplyAsync(Supplier<T> supplier) { return CompletableFuture.supplyAsync(supplier); } // Async execution with custom executor public static <T> CompletableFuture<T> supplyAsync(Supplier<T> supplier, ExecutorService executor) { return CompletableFuture.supplyAsync(supplier, executor); } // Transform result public static <T, R> CompletableFuture<R> thenApply(CompletableFuture<T> future, Function<T, R> mapper) { return future.thenApply(mapper); } // Chain futures public static <T, R> CompletableFuture<R> thenCompose(CompletableFuture<T> future, Function<T, CompletableFuture<R>> mapper) { return future.thenCompose(mapper); } // Combine two futures public static <T, U, R> CompletableFuture<R> thenCombine(CompletableFuture<T> future1, CompletableFuture<U> future2, BiFunction<T, U, R> combiner) { return future1.thenCombine(future2, combiner); } // Wait for all futures public static CompletableFuture<Void> allOf(List<CompletableFuture<?>> futures) { return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])); } // Wait for any future public static <T> CompletableFuture<Object> anyOf(List<CompletableFuture<T>> futures) { return CompletableFuture.anyOf(futures.toArray(new CompletableFuture[0])); } // Handle exceptions public static <T> CompletableFuture<T> handle(CompletableFuture<T> future, BiFunction<T, Throwable, T> handler) { return future.handle(handler); }}
// Simple async executionCompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); return "Hello"; } catch (InterruptedException e) { throw new RuntimeException(e); }});// Transform resultCompletableFuture<Integer> length = future.thenApply(String::length);// Chain operationsCompletableFuture<String> chained = future .thenApply(s -> s + " World") .thenApply(String::toUpperCase);// Combine two futuresCompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");CompletableFuture<String> combined = future1.thenCombine( future2, (s1, s2) -> s1 + " " + s2);// Wait for allList<CompletableFuture<String>> futures = Arrays.asList( CompletableFuture.supplyAsync(() -> "Task 1"), CompletableFuture.supplyAsync(() -> "Task 2"), CompletableFuture.supplyAsync(() -> "Task 3"));CompletableFuture<Void> allDone = CompletableFuture.allOf( futures.toArray(new CompletableFuture[0]));// Exception handlingCompletableFuture<String> safe = future .exceptionally(ex -> "Error: " + ex.getMessage()) .handle((result, ex) -> { if (ex != null) { return "Handled: " + ex.getMessage(); } return result; });// Get result (blocking)try { String result = future.get(); // or with timeout String result2 = future.get(5, TimeUnit.SECONDS);} catch (Exception e) { e.printStackTrace();}
Comments
No comments yet. Be the first to comment!
Please login to leave a comment.