محتويات الدورة

Java / المتوسط / الدرس 8

الأنواع العامة ولامبدا ومسارات Stream

عبّر عن عمليات عامة آمنة الأنواع وتحويلات بيانات دون أنواع خام أو آثار خفية أو افتراضات عن تنفيذ المسار.

وقت القراءة التقريبي: 4 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • شرح ثبات معاملات النوع والبدائل المقيدة.
  • قراءة لامبدا كتنفيذ عقد دالي.
  • بناء اختزال Stream حتمي دون آثار.

احفظ العلاقات بين الأنواع

تحفظ الأنواع العامة العلاقات دون تحويل كل شيء إلى Object. تعلن List<String> أن القراءة تعيد نصاً وترفض إضافة Integer عند الترجمة. تتجاوز List الخام الفحص وقد تؤجل ClassCastException بعيداً عن الإدراج. اعتبر التحذير غير المتحقق دليلاً لا ضوضاء لإسكاتها عامة.

الأنواع العامة ثابتة المعامل: ليست List<Integer> فرعاً من List<Number> رغم علاقة Integer وNumber، وإلا أمكن إدراج Double في قائمة تعد بالأعداد الصحيحة. يحد محو النوع أيضاً اختبارات التشغيل؛ ولا يمثل instanceof List<String> اختباراً عادياً لنوع قابل للتحقق. افصل ضمان الترجمة من التمثيل الفعلي.

استخدم بديلاً مقيداً لوصف اتجاه البيانات

يقرأ List<? extends Number> عناصر كـNumber من قوائم فروع مناسبة، ولا يضيف Number اعتباطياً لأن الفعلي قد يكون List<Integer>. ولوجهة تستقبل T غالباً يناسب ? super T العلاقة المعاكسة. اختر القيد وفق إنتاج النوع أو استهلاكه.

يجمع المثال كـdouble دون تغيير الإدخال فينتج6.0 من1 و2 و3. قد تفقد الدقة في مجال عشري دقيق؛ فلا تجعل المرونة العامة التمثيل الحسابي مناسباً للجميع. وثّق العدد مستقلاً عن التباين وأدرج الفراغ في العقد.

java قراءة منتج عددي دون تعديله
public class Main {
static double sum(java.util.List<? extends Number> values) {
 double total=0; for(Number n:values) total+=n.doubleValue(); return total;
}
 public static void main(String[] args) throws Exception {
System.out.println(sum(java.util.List.of(1,2,3)));
 }
}
الناتج المتوقع
6.0

يقرأ كل Integer كـNumber ويحوّل إلى double لهذا الجمع التقريبي المعلن.

عامل لامبدا كسلوك محدد النوع

تنفذ لامبدا الدالة المجردة الوحيدة لواجهة دالية. تفحص Predicate<T> شرطاً وتحول Function<T,R> قيمة وتنفذ Consumer<T> فعلاً. يحدد النوع الهدف عقد المعامل والناتج؛ وليست لامبدا ديناميكية الأنواع. مراجع الدوال صياغة بديلة لسلوك متوافق مثل String::length.

يجب أن يكون المحلي الملتقط final أو ثابتاً فعلياً، لكن مرجعه قد يشير إلى حالة متغيرة. لا يؤمن بناء لامبدا تعديل ArrayList مشتركة من مهام متزامنة. فضّل تحويلات بلا حالة في المسارات وأظهر المتعاون المتغير إذا كان الأثر مطلباً حقيقياً.

افصل الوسيط من العمل النهائي

يصف Stream مساراً على البيانات وليس مجموعة مخزنة. تكون filter وmap كسولتين وتحرك عملية نهائية مثل sum الحساب. يحتفظ المثال بالزوجي ويربعه ويجمع4 و16 فينتج20. تبقى القائمة الأصلية بلا تغيير.

يستخدم المسار عادة مرة واحدة؛ أنشئ جديداً لحساب نهائي آخر. استخدم المسارات الأولية إذا أوضحت الاختزال. لا تعتمد peek أو أثراً داخل map لتنفيذ فعل أساسي، لأن التحسين والاختصار قد يغيران العمليات الوسيطة المقيمة.

java مسار تصفية وتحويل واختزال
public class Main {

 public static void main(String[] args) throws Exception {
var values=java.util.List.of(1,2,3,4);
int answer=values.stream().filter(n->n%2==0)
 .mapToInt(n->n*n).sum();
System.out.println(answer);
System.out.println(values.size());
 }
}
الناتج المتوقع
20
4

يبقى2 و4 فيصبحان4 و16، وتظل العناصر الأصلية الأربعة في القائمة.

اطلب دليلاً قبل موازاة المسار

لا تضمن parallelStream سرعة أعلى. يهم حجم العمل والتقسيم والحجب وتنافس المجمع وتصميم الاختزال. يحتاج الاختزال عملية تجميعية ومحايداً صحيحاً؛ وقد يفسد الطرح أو مجمع مشترك غير آمن النتائج. يختلف ترتيب اللقاء من التنفيذ غير المرتب.

اختبر الفراغ والمرفوض والتكرار والحدود قبل السرعة. قارن حلقة مباشرة إن كانت أوضح. قيمة المسار عقد التحويل لا تجنب كل الحلقات. تحفظ الواجهة الجيدة علاقات الأنواع وتظهر تدفق البيانات دون إخفاء تغييرات حالة أساسية.

الأخطاء الشائعة وإصلاحها

incompatible types: List<Integer> cannot be converted to List<Number>

لماذا يحدث؟
معاملات النوع ثابتة.
كيف تصلحه؟
استخدم بديلاً مقيداً مناسباً للقراءة.
كيف تتجنب تكراره؟
وضح اتجاه البيانات في التوقيع.

ClassCastException after raw collection use

لماذا يحدث؟
كسر إدراج غير مفحوص نوع العناصر.
كيف تصلحه؟
أعد الأنواع العامة وأزل الإدراج غير الآمن.
كيف تتجنب تكراره؟
راجع التحذيرات غير المتحققة.

stream has already been operated upon or closed

لماذا يحدث؟
استهلكت العملية النهائية المسار.
كيف تصلحه؟
أنشئ مساراً جديداً من المصدر.
كيف تتجنب تكراره؟
اربط كل مسار بنتيجة نهائية واحدة.

اختبر فهمك

1. لماذا تقرأ الدالة List<? extends Number> ولا تضيف Double؟

اعرض الحل المشروح

قد يكون الإدخال List<Integer>. تصح القراءة كـNumber وتكسر إضافة Double وعد العناصر. يصف البديل جهلاً بالفرع الدقيق لا قائمة عددية قابلة للكتابة عموماً.

2. رشّح [1,2,3,4,5] لأكبر من2 واجمع ضعفها. ما النتيجة؟

اعرض الحل المشروح

تبقى3 و4 و5 وتصبح6 و8 و10، ومجموعها24. استخدم filter ثم mapToInt ثم sum وتحقق من محايد الفراغ صفر.

أهم ما تعلمته

  • تحفظ الأنواع العامة العلاقات دون تحويلات خام.
  • تنفذ لامبدا عقود سلوك محددة النوع.
  • المسارات كسولة وأحادية الاستخدام وليست نتائج مخزنة.

المراجع الرسمية