0Pricing
Java Academy · درس

التسلسل باستخدام thenApply وthenCompose

حوّل النتائج باستخدام thenApply وسلسل الخطوات غير المتزامنة باستخدام thenCompose لتجنب futures المتداخلة

التسلسل باستخدام 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 (أو في Executor مقدَّم)، مما يحرّر الخيط الذي أكمل العملية فورًا.

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: تسطيح Futures المتداخلة

يشبه thenCompose(Function<T, CompletionStage<U>>) عملية flatMap الخاصة بـ futures. فهو يتجنّب 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 الخاص بـ futures). يضيف handle وwhenComplete معالجة الأخطاء والتأثيرات الجانبية. أنشئ المسارات من اليسار إلى اليمين لتسهيل قراءتها.

الأسئلة الشائعة

هل درس «التسلسل باستخدام thenApply وthenCompose» مجاني؟

نعم — نص درس «التسلسل باستخدام thenApply وthenCompose» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.

ماذا ستتعلم في «التسلسل باستخدام thenApply وthenCompose»؟

حوّل النتائج باستخدام thenApply وسلسل الخطوات غير المتزامنة باستخدام thenCompose لتجنب futures المتداخلة تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟

لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «التسلسل باستخدام thenApply وthenCompose»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟

نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. إنشاء CompletableFutures وإكمالها
  2. التسلسل باستخدام thenApply وthenCompose
  3. دمج Futures: ‏allOf وanyOf
  4. معالجة الأخطاء وخط أنابيب HTTP غير المتزامن
← العودة إلى Java Academy