Asynchronous Programming Summary
CompletableFuture Concept
- Represents a future result
- Supports non-blocking operations
- Enables asynchronous programming
- Example:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> expensiveOperation());
Creating CompletableFuture
-
Static Factory Methods:
// Complete future CompletableFuture.completedFuture(value); // Run async task CompletableFuture.runAsync(() -> task()); // Supply async result CompletableFuture.supplyAsync(() -> compute());
-
Multiple Futures:
CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2); CompletableFuture<Object> any = CompletableFuture.anyOf(future1, future2);
Chaining Operations
-
Transformations:
future.thenApply(x -> x * 2) // map .thenCompose(x -> compute(x)) // flatMap .thenCombine(other, (x,y) -> x + y);
-
Side Effects:
future.thenAccept(System.out::println) // consumer .thenRun(() -> cleanup()); // runnable
Exception Handling
future.exceptionally(ex -> {
System.err.println(ex);
return defaultValue;
})
.handle((result, ex) -> {
if (ex != null) {
return handleError(ex);
}
return result;
});
Async vs Sync Methods
-
Async Methods:
// Executes in different thread future.thenApplyAsync(x -> process(x)); future.thenComposeAsync(x -> compute(x)); future.thenCombineAsync(other, (x,y) -> combine(x,y));
-
Sync Methods:
// Executes in same thread future.thenApply(x -> process(x)); future.thenCompose(x -> compute(x)); future.thenCombine(other, (x,y) -> combine(x,y));
Best Practices
- Use async operations for I/O
- Handle exceptions properly
- Don't block unnecessarily
- Consider thread pools
- Chain operations efficiently
- Test async behavior
- Example:
```java
CompletableFuture
result = CompletableFuture.supplyAsync(() -> readFile()) .thenApplyAsync(content -> process(content)) .exceptionally(ex -> handleError(ex));