0Pricing
Java Academy · Урок

Объединение 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 thread

thenAccept: обработка без возврата результата

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.425

thenCompose: выравнивание вложенных 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 — локальная установка не требуется.

Все уроки этого курса

  1. Создание и завершение CompletableFutures
  2. Объединение thenApply и thenCompose в цепочки
  3. Объединение будущих объектов: allOf и anyOf
  4. Обработка ошибок и асинхронный конвейер HTTP
← Назад к Java Academy