0Pricing
Java Academy · Lekcja

Łączenie za pomocą thenApply i thenCompose

Przekształcaj wyniki przez thenApply i spłaszczaj asynchroniczne kroki przez thenCompose, aby unikać zagnieżdżonych future.

Łączenie za pomocą thenApply i thenCompose to bezpłatna lekcja Java Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Java Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Java Academy zawiera 4 lekcji w sumie.

thenApply: Przekształcanie wyniku

thenApply(Function) stosuje synchroniczną funkcję do wyniku ukończonego future i zwraca nowy future z przekształconym typem. Nie uruchamia nowego zadania asynchronicznego.

CompletableFuture<String> nameFuture = CompletableFuture
    .supplyAsync(() -> 42L)            // CF<Long>
    .thenApply(id -> "User#" + id);    // CF<String>
System.out.println(nameFuture.join()); // "User#42"

thenApplyAsync: Przekształcanie w wątku

thenApplyAsync uruchamia funkcję przekształcającą w puli ForkJoinPool lub w puli przekazanego executora, natychmiast zwalniając wątek kończący obliczenie.

CompletableFuture<String> result = fetchUserAsync()
    .thenApplyAsync(user -> serialize(user)); // runs on pool thread

thenAccept: Przetwarzanie bez zwracania wyniku

thenAccept(Consumer) przetwarza wynik, ale zwraca CompletableFuture<Void>. Należy używać go jako ostatniego kroku potoku, gdy nie trzeba przekazywać dalej wartości.

fetchUserAsync()
    .thenApply(User::getName)
    .thenAccept(name -> System.out.println("Hello, " + name));

thenRun: Uruchamianie po ukończeniu

thenRun(Runnable) uruchamia zadanie po ukończeniu future, ignorując wynik. Dobrze nadaje się do zamykania zasobów lub wywoływania efektów ubocznych.

downloadFileAsync(url)
    .thenRun(() -> System.out.println("Download complete"));

Łączenie wielu wywołań thenApply

Wiele wywołań thenApply tworzy potok. Każdy krok otrzymuje wynik poprzedniego kroku.

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: Spłaszczanie zagnieżdżonych future

thenCompose(Function<T, CompletionStage<U>>) działa podobnie do flatMap dla future. Zapobiega powstaniu CompletableFuture<CompletableFuture<T>>, spłaszczając zagnieżdżony 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 dla sekwencyjnych wywołań asynchronicznych

Należy używać thenCompose, gdy każdy asynchroniczny krok zależy od wyniku poprzedniego — dzięki temu kroki są wykonywane sekwencyjnie i zależą od wyników.

fetchUser(userId)
    .thenCompose(user -> fetchOrders(user.getId()))
    .thenCompose(orders -> computeTotal(orders))
    .thenAccept(total -> System.out.println("Total: " + total));

thenApply a thenCompose

thenApply: odwzorowuje T -> U (synchroniczne przekształcenie). thenCompose: odwzorowuje T -> CompletableFuture<U> i spłaszcza wynik. Należy używać compose, gdy następny krok również jest asynchroniczny.

Obsługa błędów pośrednich za pomocą handle

handle(BiFunction<T, Throwable, U>) jest wywoływane niezależnie od tego, czy future został ukończony pomyślnie, czy wyjątkowo, co pozwala odzyskać sprawność lub przekształcić błędy w środku potoku.

fetchUser(id)
    .thenApply(User::getProfile)
    .handle((profile, ex) -> {
        if (ex != null) return Profile.empty(); // recover
        return profile;
    })
    .thenAccept(System.out::println);

whenComplete: Efekt uboczny po dowolnym wyniku

whenComplete(BiConsumer) jest wywoływane po ukończeniu obliczenia (pomyślnym lub wyjątkowym) w celu rejestrowania informacji lub czyszczenia zasobów. W przeciwieństwie do handle nie zmienia wyniku.

fetchAsync()
    .whenComplete((result, ex) -> {
        if (ex != null) log.error("Failed", ex);
        else            log.info("Result: " + result);
    });

Przykład potoku bez blokowania

Należy utworzyć w pełni nieblokujący potok: pobrać użytkownika, pobrać jego zamówienia i obliczyć podsumowanie — wszystkie kroki są wykonywane asynchronicznie, a każdy zależy od poprzedniego.

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());

Szybkie sprawdzenie

Kiedy należy użyć thenCompose zamiast thenApply?

Podsumowanie

thenApply przekształca wartości synchroniczne w potoku. thenCompose łączy kroki asynchroniczne (działa jak flatMap dla future). handle / whenComplete dodają obsługę błędów i efekty uboczne. Dla czytelności należy budować potoki od lewej do prawej.

Często zadawane pytania

Czy lekcja „Łączenie za pomocą thenApply i thenCompose” jest bezpłatna?

Tak — pełny tekst „Łączenie za pomocą thenApply i thenCompose” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Java Academy, przejdź na CoddyKit PRO. Kurs Java Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Łączenie za pomocą thenApply i thenCompose”?

Przekształcaj wyniki przez thenApply i spłaszczaj asynchroniczne kroki przez thenCompose, aby unikać zagnieżdżonych future. Ćwiczysz Java Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Java Academy?

Nie wymagamy żadnego doświadczenia. Java Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Łączenie za pomocą thenApply i thenCompose”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Java Academy?

Tak. Każda lekcja Java Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Tworzenie i uzupełnianie CompletableFuture
  2. Łączenie za pomocą thenApply i thenCompose
  3. Łączenie future: allOf i anyOf
  4. Obsługa błędów i asynchroniczny potok HTTP
← Powrót do Java Academy