مقدمة عن الLambda Expressions في Java 8

Ammar AlTahhanمنذ 7 سنوات

السلام عليكم،

في هذه المقالة سنطلع على مقدمة لأهم ما قدمته الJava في اصدارها الثامن الجديد ألا وهي ال Lambda Expressions.

 

هذه المقالة ستفترض:

  • بأنك على معرفة تامة بالبرمجة عن طريق الجافا في اصداراتها السابقة
  • معرفتك عن مبادئ البرمجة المتعلقة بالObject-Oriented Languages
  • معرفتك لأهم أساسيات الجافا (Inheritance, Polymorphism, Abstraction and Encapsulation)
  • لن تفترض معرفتك اي شيء متعلق بالنسخة الثامنة من جافا

 

- لماذا ال Lambda ؟

من الصعب علي أن أشرح مدى أهمية وفوائد ال Lambda Expressions، لنفهم أهميتها تماما لابد من فهمها بالأصل، لذلك عليكم أن تثقوا بي في ما سأقوله (سيتضح المعنى أكثر كلما تقدمت بالشرح):

  1. لمن استخدم الجافا من قبل، يعلم أنها مبنية تماما على البرمجة الموضوعية (Object-Oriented Programming)، نستطيع الآن ان نضيف اليها نوع آخر وهو البرمجة الوظيفية (Functional Programming).
  2. ستعطي المبرمج امكانية كتابة اكواد مختصرة وقابلة للقراءة أكثر.
  3. ستضيف امكانية كتابة API's بسهولة اكبر وستسهل عملية استخدامها لاحقا.
  4. ستضيف الدعم للمعالجة المتعددة (Parallel Processing).

سنركز على أول فائدة ونشرحها باستفاضة تاليًا.

 

- ما الفرق بين ال(Object-Oreiented and Functional Programming) ؟

سأجيب على هذا السؤال باجابتي على سؤال أخر، هل فعلا الجافا تحتاج الى Functional Programming ؟

من سنين طويلة، والجافا كانت (ولا زالت وستظل) تعتمد بشكل أساسي على ال OO-Programming، ولا يوجد أي شيء لا تستطيع فعله بالجافا وتستطيع فعله بFunctional Language أخرى.

إذا لماذا ؟ ال Functional Programming لا تضيف أي شيء جديد، سوا امكانية كتابة كود قابل للقراءة بسهولة أكبر وتمكنك من اكتشاف الأخطاء واصلاحها بسهولة.

إذا، فكر بالFunctional Programming كأنها أداة اضافية للOO-Programming لتساعدنا وتسهل علينا كتابة الأكواد بالجافا.

 

- ما هي المشاكل التي تستدعي استخدام الLambda Expressions ؟

سأوضح طريقة استعمال الLambda لحل بعض المشاكل التي تواجهنا عن طريق طرح المثال التالي:

لنفترض بأنني أريد ان انشئ البرنامج الصغير المشهور لطباعة جملة (!Hello World) عن طريق استدعاء Method اخرى في الMain Method:


public class Greeter {

	public void greet () {
		System.out.print("Hello World!");
	{

	public static void main (String[] args) {
		Greeter greeter = new Greeter();
		greeter.greet();
    }

}

عندما يعمل هذا البرنامج الصغير، سيطبع لي جملة Hello World! بالكونسول.

الآن، لنفترض بأني اريد ان اعدل الميثود greet() لأجعلها تأخذ انبوت معين، وبناء عليه تطبع شي مختلف لكل انبوت مختلف.

المبرمج العادي سيفكر مباشرة بالSwitch statement وهو تقريبا الحل الأبسط للذهن ولكنه حل غير فعال.

نريد أن نجد حل لهذه المشكلة، بحيث أننا نستطيع ان ندخل (سلوك) معين للميثود، بدلا من ان ندخل لها مجرد رقم أو جملة، نريد طريقة لإخبار الميثود مباشرة بما نريده عن طريق ادخال مجموعة من الأوامر (a block of code) مرة واحدة.

قبل ان تأتي الجافا 8، كان بامكاننا حل هذه المشكلة عن طريق انشاء Interface و Class آخرين مساعدين كالتالي:


public interface GreetingInterface {
	public void perform();
}


public class GreetingClass implements GreetingInterface {
	@Override
	public void perform() {
		System.out.print("Hello World!");
	}
}

ومن ثم نتجه لتعديل الClass الأول ليصبح كالتالي:


public class Greeter {

	public void greet (GreetingInterface greeting) {
		greeting.perform();
	{

	public static void main (String[] args) {
		Greeter greeter = new Greeter();
		GreetingClass greetingClass = new GreetingClass();
		greeter.greet(greetingClass);
    }

}

نلاحظ أن الميثود greet() الآن اصبحت تستقبل أوبجكت من Class implementeing GreetingInterface، بكلمات أخرى، أصبحت تستقبل (سلوك) لتنفذه بدلا من معطى لتتصرف بناء عليه.

الآن نستطيع أن نعدل الميثود preform() في كلاس GreetingClass ليتعدل سلوك الميثود greet() بناء عليه.

لكن هذه الطريقة طويلة وتتطلب انشاء Interface و Class آخرين فقط للقيام بمهمة بسيطة كهذه!

هناك حل آخر لاختصار كل هذه الأكواد وتجاوز مشكلة انشاء كلاس جديد وهو عن طريق استخدام الAnonymous Inner Class. لن أتطرق لهذا الحل للحاجه لشرح العديد من المفاهيم بالرغم من بساطة الكود المستخدم (ولأن محور المقالة هو استخدام الLambda لحل المشكلة، وهو ما سنتحدث عنه تاليا).

 

- كيف استخدم الLambda Expression ؟

كل ما سبق كان مقدمة للتالي: استخدام الLambda Expression لادخال مجموعة من الأوامر كInput الى الميثود greet().

قبل طرح الحل، تخيلوا معي لو استطعنا ان نحفظ مجموعة من الأوامر في variable معين، (لاحظوا انني قلت حفظ مجموعة من الأوامر وليس نتيجة تنفيذ هذه الأوامر).

ماذا لو كان بامكاننا ان نكتب شيئا مثل:


aBlockOfCode = public void printing () {
					   System.out.print("Hello World!");
				   }

بحيث يكون اسم الVariable عبارة عن printingFunction وبداخله 3 سطور من الأوامر. فعليا، هذا ما تتيحه لنا الLambda Expressions.

مع تتطور الجافا، الآن أصبح الcompiler ذكي كفاية للتعرف على الميثود من دون تحديد (modifier, return type, or the name) في تعريف الميثود، كل ما عليك هو استخدام الرمز الخاص بالLambda Expressions وهو <- ليكون كالتالي:


//nameOfTheVariable = (LIST OF INPUTS) -> {LIST OF COMMAND LINES};
printingFuncion = () -> System.out.print("Hello World!");

لكي تكتمل العبارة، لابد من اختيار النوع ال(Type) الصحيح، ولكن ماهو نوع هذا الVariable الجديد؟

الجافا اختارت ان يكون نوع هذا الفاريابل عبارة عن Interface بحيث يحتوي هذا ال Interface على ميثود لها Signature مطابق لLambda Expression:


public class Test {
  public static void main(String[] args) {
    GreetingInterface printingFunction = () -> System.out.print("Hello World!");
  }
}

public interface GreetingInterface {
	void perform();
}

لاحظ ان الLambda Expression لا تحتوي على أي انبوت (وكذلك الميثود الموجودة بال Interface)

لاحظ أيضا ان الLambda Expression لا تعيد أي قيمة (وكذلك الميثود الموجودة بال Interface من نوع void)

لاحظ أيضا ان اسم الميثود بال Interface غير مهم أبدا، ما يهم هو اسم الInterface نفسه لأنك ستستعمله ك Type لLambda Expression.

 

مثال آخر لLambda Expression لجمع رقمين:


public class Test {
  public static void main(String[] args) {
    Add addingFunction = (int a, int b) -> a + b;
  }
}

public interface Add {
  int addingMethod(int a, int b);
}

 

بقي علينا استخدام هذا الExpression في الميثود، وتستطيع فعل ذلك عن طريق استدعاء الميثود الموجودة بالInterface.

بالعودة الى مثال Hello World!:


public class Greeter {

  public void greet (GreetingInterface greeting) {
      greeting.perform();
  {

  public static void main (String[] args) {
      GreetingInterface printingFunction = () -> System.out.print("Hello World!");
      greeter.greet(printingFunction.perform());
  }

}
    
public interface GreetingInterface {
  void perform();
}

 

ملاحظات:

  • اذا كانت الLambda تحتوي على أكثر من سطر يجب استخدام ال{}  بعد استخدام الرمز <-
  • لا داعي لاستخدام الreturn Statement في حالة السطر الواحد (اذا اردت استخدام الreturn Statement يجب استخدام ال{})
  • الInterface المستعمل كType للLambda Expression يجب ان يكون Functional Interface (أي يحتوي على ميثود واحدة ففقط بsignature مطابق تماما للLambda Expression)

 

الى هنا نصل لختام هذا الموضوع.

وفق الله الجميع لما يحبه ويرضاه.

كلمات دليلية:
2
إعجاب
4487
مشاهدات
0
مشاركة
1
متابع
متميز
محتوى رهيب

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !