Объединение thenApply и thenCompose в цепочки
Преобразуйте результаты с помощью thenApply и объединяйте асинхронные шаги flatMap с помощью thenCompose, избегая вложенных будущих объектов.
«Объединение thenApply и thenCompose в цепочки» — бесплатный урок Java Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
thenApply: преобразование результата
thenApply(Function) применяет синхронную функцию к результату завершённого future и возвращает новый future с преобразованным типом. Новый асинхронный процесс при этом не запускается.
CompletableFuture<String> nameFuture = CompletableFuture
.supplyAsync(() -> 42L) // CF<Long>
.thenApply(id -> "User#" + id); // CF<String>
System.out.println(nameFuture.join()); // "User#42"thenApplyAsync: преобразование в потоке
thenApplyAsync выполняет функцию преобразования в ForkJoinPool или переданном исполнителе, немедленно освобождая поток, завершивший предыдущую операцию.
CompletableFuture<String> result = fetchUserAsync()
.thenApplyAsync(user -> serialize(user)); // runs on pool threadthenAccept: обработка без возврата результата
thenAccept(Consumer) обрабатывает результат, но возвращает CompletableFuture<Void>. Используйте его как последний шаг конвейера, когда не нужно передавать значение дальше.
fetchUserAsync()
.thenApply(User::getName)
.thenAccept(name -> System.out.println("Hello, " + name));thenRun: выполнение после завершения
thenRun(Runnable) выполняет задачу после завершения future, игнорируя результат. Это удобно для закрытия ресурсов или запуска побочных эффектов.
downloadFileAsync(url)
.thenRun(() -> System.out.println("Download complete"));Объединение нескольких вызовов thenApply
Несколько вызовов thenApply образуют конвейер. Каждый шаг получает результат предыдущего шага.
CompletableFuture<Double> result = CompletableFuture
.supplyAsync(() -> " 42.5 ")
.thenApply(String::trim)
.thenApply(Double::parseDouble)
.thenApply(d -> d * 1.21); // apply 21% VAT
System.out.println(result.join()); // 51.425thenCompose: выравнивание вложенных future
thenCompose(Function<T, CompletionStage<U>>) подобен flatMap для future. Он устраняет CompletableFuture<CompletableFuture<T>>, выравнивая вложенный future.
// Wrong with thenApply — returns CF<CF<Order>>:
CompletableFuture<CompletableFuture<Order>> nested =
fetchUser(id).thenApply(u -> fetchLatestOrder(u.getId()));
// Correct with thenCompose — returns CF<Order>:
CompletableFuture<Order> flat =
fetchUser(id).thenCompose(u -> fetchLatestOrder(u.getId()));thenCompose для последовательных асинхронных вызовов
Используйте thenCompose, когда каждый асинхронный шаг зависит от результата предыдущего, делая шаги последовательными и зависимыми от результата.
fetchUser(userId)
.thenCompose(user -> fetchOrders(user.getId()))
.thenCompose(orders -> computeTotal(orders))
.thenAccept(total -> System.out.println("Total: " + total));thenApply и thenCompose
thenApply: преобразует T -> U (синхронное преобразование). thenCompose: преобразует T -> CompletableFuture<U> и выравнивает результат. Используйте compose, когда следующий шаг тоже является асинхронным.
Обработка промежуточных ошибок с помощью handle
handle(BiFunction<T, Throwable, U>) вызывается независимо от того, завершился ли future обычным образом или с исключением, что позволяет восстановиться после ошибки или преобразовать её в середине конвейера.
fetchUser(id)
.thenApply(User::getProfile)
.handle((profile, ex) -> {
if (ex != null) return Profile.empty(); // recover
return profile;
})
.thenAccept(System.out::println);whenComplete: побочный эффект после любого результата
whenComplete(BiConsumer) вызывается после завершения, обычного или с исключением, для журналирования или очистки. В отличие от handle, этот метод не изменяет результат.
fetchAsync()
.whenComplete((result, ex) -> {
if (ex != null) log.error("Failed", ex);
else log.info("Result: " + result);
});Пример неблокирующего конвейера
Составьте полностью неблокирующий конвейер: получите пользователя, получите его заказы и вычислите сводку. Все шаги выполняются асинхронно, каждый зависит от предыдущего.
CompletableFuture<String> summary =
fetchUser(userId)
.thenCompose(u -> fetchOrders(u.getId()))
.thenApply(orders -> orders.size() + " orders")
.exceptionally(ex -> "Error: " + ex.getMessage());
System.out.println(summary.join());Быстрая проверка
Когда следует использовать thenCompose вместо thenApply?
Итоги
thenApply преобразует синхронные значения в конвейере. thenCompose объединяет асинхронные шаги (flatMap для future). handle и whenComplete добавляют обработку ошибок и побочные эффекты. Стройте конвейеры слева направо для удобства чтения.
Часто задаваемые вопросы
Урок «Объединение thenApply и thenCompose в цепочки» бесплатный?
Да — полный текст урока «Объединение thenApply и thenCompose в цепочки» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Объединение thenApply и thenCompose в цепочки»?
Преобразуйте результаты с помощью thenApply и объединяйте асинхронные шаги flatMap с помощью thenCompose, избегая вложенных будущих объектов. Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Объединение thenApply и thenCompose в цепочки»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Создание и завершение CompletableFutures
- Объединение thenApply и thenCompose в цепочки
- Объединение будущих объектов: allOf и anyOf
- Обработка ошибок и асинхронный конвейер HTTP