Как выполнить асинхронные задачи и объединить результаты
Короткий ответ
supplyAsync() запускает задачу в фоне, thenApply() описывает, что сделать с результатом, join() ждёт итог:
void main() {
CompletableFuture<String> greeting = CompletableFuture
.supplyAsync(() -> "anna")
.thenApply(String::toUpperCase)
.thenApply(name -> "Hello, " + name);
IO.println(greeting.join());
}Результат:
Hello, ANNAОбъединить два результата
thenCombine() ждёт две независимые задачи и объединяет их результаты:
int load(String what, int value) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return value;
}
void main() {
var price = CompletableFuture.supplyAsync(() -> load("price", 120));
var discount = CompletableFuture.supplyAsync(() -> load("discount", 20));
IO.println(price.thenCombine(discount, (p, d) -> p - d).join());
}Результат:
100Дождаться всех
allOf() завершается, когда готовы все задачи:
void main() {
var futures = List.of(
CompletableFuture.supplyAsync(() -> 1),
CompletableFuture.supplyAsync(() -> 2),
CompletableFuture.supplyAsync(() -> 3));
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
IO.println(futures.stream().mapToInt(CompletableFuture::join).sum());
}Результат:
6Обработка ошибок
exceptionally() подставляет значение, если на каком-то шаге произошла ошибка:
void main() {
int value = CompletableFuture.supplyAsync(() -> Integer.parseInt("x"))
.exceptionally(error -> {
IO.println("Failed: " + error.getCause().getMessage());
return 0;
})
.join();
IO.println(value);
}Результат:
Failed: For input string: "x"
0Частая ошибка
Забыть дождаться результата. Программа завершается, а фоновые задачи из общего пула не успевают выполниться — их вывод просто пропадает:
void main() {
CompletableFuture.runAsync(() -> {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
IO.println("never printed");
});
IO.println("main finished");
}Результат:
main finishedВызывайте join() или get(), если результат нужен до выхода из программы.
Функции из этого ответа
- CompletableFuture.supplyAsync() — Запускает вычисление асинхронно и возвращает `CompletableFuture`.
- CompletableFuture.thenApply() — Добавляет шаг, который преобразует результат, когда тот будет готов.
- CompletableFuture.thenCombine() — Объединяет результаты двух независимых задач, когда готовы обе.
- CompletableFuture.join() — Ждёт результат `CompletableFuture`; ошибки приходят как непроверяемые исключения.