من الفئات المجهولة إلى تعبيرات Lambda
من الفئات المجهولة إلى تعبيرات Lambda
أتاحت Java دومًا إمكانية تمرير السلوك كـ object. قبل وجود تعبيرات lambda، كانت الطريقة المعتمدة هي الفئة المجهولة (anonymous class) — تنفيذ مضمّن بلا اسم لواجهة (أو فئة مجردة) يُكتب مباشرةً في مكان الاستخدام. تعبيرات lambda لا تضيف مفهومًا جديدًا؛ إنها فقط تزيل الإسهاب المحيط بهذه الفكرة.
نمط الفئة المجهولة
لنفترض أنك تريد ترتيب قائمة من السلاسل النصية حسب الطول. قبل Java 8 كنت ستكتب:
هذا يعمل بشكل مثالي. لكن انظر كم عدد الأسطر اللازمة للتعبير عن فكرة بسيطة واحدة: المقارنة حسب الطول. عليك:
- كتابة
new Comparator<String>() { }لإنشاء الفئة المجهولة. - كتابة التعليق التوضيحي
@Overrideوتوقيع الدالة الكامل. - ثم — أخيرًا — كتابة السطر الوحيد من المنطق الذي تهتم به فعلًا.
يُسمى هذا النمط أحيانًا الشفرة الزائدة (boilerplate): كود مطلوب هيكليًا لكنه لا يعبّر عن أي نية حقيقية. نسبة الإسهاب إلى المنطق هنا تقريبًا 5:1.
تعبيرات Lambda
تعبير lambda هو طريقة مختصرة لكتابة نفس الفئة المجهولة تمامًا — عندما تحتوي الواجهة على دالة مجردة واحدة فقط. إليك نفس الترتيب مُعاد كتابته بتعبير lambda:
سطر واحد. لا تصريح فئة، لا تعليق توضيحي، لا توقيع دالة. يستنتج المُصرِّف أنواع a وb من السياق (المتوقع هو Comparator<String>، لذا كلاهما String).
حالة شائعة أخرى: Runnable
Runnable هي إحدى أقدم الواجهات ذات الدالة الواحدة في Java. مع فئة مجهولة:
مع تعبير lambda:
الأقواس () تشير إلى عدم وجود معاملات. الجسم هو العبارة الواحدة التي تأتي بعد السهم.
ما يراه المُصرِّف
لا يستطيع المُصرِّف استبدال فئة مجهولة بتعبير lambda إلا إذا كانت الواجهة واجهة وظيفية (functional interface) — أي تُعلن عن دالة مجردة واحدة فقط. Comparator وRunnable وعشرات الواجهات الأخرى في JDK تستوفي هذا الشرط. التعليق الاختياري @FunctionalInterface يتيح لك تعريف واجهاتك الخاصة:
كلا المتغيرين يحملان شيئًا يستجيب لـ greet(String). تعبير lambda هو مجرد طريقة أقصر للتعبير عن ذلك.
لماذا يهمنا هذا
إزالة الإسهاب ليست مجرد تجميل. عندما تختفي الضوضاء، تصبح النية — ما يفعله الكود فعلًا — هي الشيء الوحيد الذي يراه القارئ. هذا التحوّل يفتح باب أسلوب برمجي تُمرَّر فيه أجزاء صغيرة من السلوك وتُجمَّع وتُؤلَّف بنفس سهولة تمرير البيانات. كل درس في هذا البرنامج التعليمي يبني على هذه الفكرة.
-> المدخلات (الجانب الأيسر) عن النتيجة (الجانب الأيمن). درّب نفسك على قراءة (a, b) -> Integer.compare(a.length(), b.length()) على أنها "بمعطى a و b، أنتج Integer.compare لطوليهما". الأنواع مجرد ضجيج يتعامل معه المُصرِّف نيابةً عنك.
الخلاصة
تتيح الفئات المجهولة تمرير السلوك كـ object لكنها تتطلب قدرًا كبيرًا من الكود الهيكلي الزائد. تعبيرات lambda تعبّر عن نفس الفكرة بصياغة مختصرة (parameters) -> body، شريطة أن يكون النوع المستهدف واجهة وظيفية. يستكشف باقي هذا البرنامج التعليمي المجموعة الغنية من الواجهات الوظيفية التي يوفّرها الـ JDK، والطرق القوية لتأليف تعبيرات lambda وتركيبها.