Java Future və CompletableFuture
Future Nədir?
Future asynchronous əməliyyatların nəticəsini təmsil edir. Əməliyyat tamamlanmamış ola bilər və nəticə gələcəkdə əldə ediləcək.
Future Interface
Basic Usage
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future = executor.submit(() -> {
Thread.sleep(2000);
return "Hello from Future!";
});
// Nəticəni əldə et (blocking)
String result = future.get(); // 2 saniyə gözləyəcək
System.out.println(result);
executor.shutdown();
Future Metodları
Future<Integer> future = executor.submit(() -> {
Thread.sleep(3000);
return 42;
});
// Status yoxlama
boolean isDone = future.isDone(); // false (əvvəlcə)
boolean isCancelled = future.isCancelled(); // false
// Timeout ilə
try {
Integer result = future.get(1, TimeUnit.SECONDS); // TimeoutException
} catch (TimeoutException e) {
System.out.println("Timeout!");
}
// Cancel etmək
boolean cancelled = future.cancel(true); // true = interrupt if running
CompletableFuture
Java 8-də təqdim edilmiş, daha güclü Future implementasiyası.
Simple Usage
// Async task yaratmaq
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
return "Error";
}
return "Hello CompletableFuture!";
});
// Nəticəni işləmək (non-blocking)
future.thenAccept(System.out::println);
// Blocking get
String result = future.get();
Chaining Operations
thenApply() - Transform
CompletableFuture<Integer> future = CompletableFuture
.supplyAsync(() -> "42")
.thenApply(Integer::parseInt)
.thenApply(n -> n * 2);
future.thenAccept(System.out::println); // 84
thenCombine() - Combine Two Futures
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "World");
CompletableFuture<String> combined = future1.thenCombine(future2,
(s1, s2) -> s1 + " " + s2);
combined.thenAccept(System.out::println); // Hello World
Error Handling
handle() - Handle Both Result and Exception
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> {
if (Math.random() > 0.5) {
throw new RuntimeException("Random error!");
}
return "Success";
})
.handle((result, ex) -> {
if (ex != null) {
return "Error: " + ex.getMessage();
}
return result;
});
exceptionally() - Handle Only Exceptions
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> {
throw new RuntimeException("Error occurred");
})
.exceptionally(ex -> "Default value");
future.thenAccept(System.out::println); // Default value
Combining Multiple Futures
allOf() - Wait for All
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> "Task 1");
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> "Task 2");
CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> "Task 3");
CompletableFuture<Void> allFutures = CompletableFuture.allOf(f1, f2, f3);
allFutures.thenRun(() -> {
try {
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
} catch (Exception e) {
e.printStackTrace();
}
});
anyOf() - First to Complete
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(2000); } catch (InterruptedException e) {}
return "Slow task";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(1000); } catch (InterruptedException e) {}
return "Fast task";
});
CompletableFuture<Object> firstCompleted = CompletableFuture.anyOf(future1, future2);
firstCompleted.thenAccept(System.out::println); // Fast task
Practical Examples
Parallel Processing
public CompletableFuture<String> fetchUserData(int userId) {
return CompletableFuture.supplyAsync(() -> {
// Simulate HTTP call
try { Thread.sleep(1000); } catch (InterruptedException e) {}
return "User data for ID: " + userId;
});
}
public CompletableFuture<String> fetchUserPosts(int userId) {
return CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(800); } catch (InterruptedException e) {}
return "Posts for user: " + userId;
});
}
// Parallel fetch
CompletableFuture<String> userData = fetchUserData(123);
CompletableFuture<String> userPosts = fetchUserPosts(123);
CompletableFuture<String> combined = userData.thenCombine(userPosts,
(data, posts) -> data + "\n" + posts);
Best Practices
-
Non-blocking operations istifadə edin:
// Blocking (pis)
String result = future.get();
// Non-blocking (yaxşı)
future.thenAccept(System.out::println); -
Error handling unutmayın:
future
.thenApply(this::process)
.exceptionally(ex -> "Default value"); -
Custom executor istifadə edin:
ExecutorService executor = Executors.newFixedThreadPool(4);
CompletableFuture.supplyAsync(task, executor); -
join() vs get():
// join() - unchecked exception
String result = future.join();
// get() - checked exception (try-catch lazım)
String result = future.get(); -
Timeout with Default:
CompletableFuture<String> future = CompletableFuture
.supplyAsync(() -> slowOperation())
.completeOnTimeout("Default", 2, TimeUnit.SECONDS);
Common Patterns
Sequential vs Parallel
// Sequential (3 saniyə)
String result1 = task1(); // 1 saniyə
String result2 = task2(); // 1 saniyə
String result3 = task3(); // 1 saniyə
// Parallel (1 saniyə)
CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> task1());
CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> task2());
CompletableFuture<String> f3 = CompletableFuture.supplyAsync(() -> task3());
CompletableFuture.allOf(f1, f2, f3).join();
Pipeline Processing
CompletableFuture<String> pipeline = CompletableFuture
.supplyAsync(() -> "input")
.thenApply(this::step1)
.thenApply(this::step2)
.thenApply(this::step3)
.exceptionally(ex -> "Error: " + ex.getMessage());
Conditional Processing
CompletableFuture<String> result = CompletableFuture
.supplyAsync(() -> getData())
.thenCompose(data -> {
if (data.isEmpty()) {
return CompletableFuture.completedFuture("No data");
}
return CompletableFuture.supplyAsync(() -> processData(data));
});
Üstünlükləri
- Non-blocking - Thread-ləri blok etmir
- Composable - Əməliyyatları birləşdirmək asan
- Error handling - Exception-ları idarə etmək asan
- Performance - Parallel işləmə imkanı
- Readable - Kod oxunaqlıdır