سؤال

سلام عليكم

 

مع إطلاق الإصدار الثامن من جافا (java 8) كان أكثر شيء جلب انتباه المطورين هو إضافة تقنية lambda التي هي موجودة في  اللغات التي توصف بأنها  functional

 

أصل المشكلة التي حلتها lambda 

 

في الجافا لا يمكننا أن نمرر باراميتر parametre إلى أي دالة إلا احد اثنين إما : 

      مؤشر (référence)  نحو متغير أولي 

     أو مؤشر نحو كائن

int x;String y;

ولا يمكننا أن نمرر دالة كبراميتير إلى دالة اخرى

لان الجافا لغة كائنية 100/100 فكل شيء فيها هو كائن

 

 

 

كيف كانت تتعامل الجافا مع مثل هذه المشكلة قبل الإصدار الثامن

 

في الطريقة التقليدية عندما نريد ان نمرر دالة إلى دالة أخرى كنا نقوم بخطوتين

أولا إنشاء interface يحتوي دالة واحدة  (هي التي ستُمرَر)

ثانيا نقوم ب implimentation  للأنترفاس داخل قوسي الدالة الأم

 

وللتوضيح نأخذ المثال الأكثر شهرة في الجافا وهو عندما نريد إنشاء thread

 

من قرأ جيدا فصول الجافا se يعرف أنه إذا اراد إنشاء thread

فإما أن يرث كلاس جديد من الكلاس Thread  وهذ الطريقة ليست مما نحن فيه

وإما أن يقوم ب implimentation لل interface --->Runnable

 

 

هذه هي Runnable Interface

public interface Runnable {       public abstract void run();}

وهذه هي الطريقة التي وصفتها 

public class JavaApplication5{  public static void main(String[] args)  {    Thread th = new Thread(new Runnable()    {      @Override      public void run()      {        System.out.print("Salam ahmed");      }    });    th.start();  }}

الآن  مع التقنية الحديثة صار الأمر اسهل ، فلسنا بحاجة  لل  implimentation  ولا  Override

 

وإليكم  طريقة إنشاء ثريد بالتقنية lambda

public class JavaApplication5{      public static void main(String[] args)      {	Thread th2 = new Thread(() -> System.out.println("Salam ahmed !"));	th2.start();      }}

هكذا أفضل اليس كذالك

 

 

ما هي lambda ؟

 

Lambda هي دالة مجهولة (anonymous function)

ننشأها لأداء مهمة ما ، وجودها يكون مؤقتا فقط لأداء تلك المهمة

 

 

Syntaxe

 

الكتابة العامة للدالة lambda  هي

(paramètres) -> expression_simple

أو

(paramètres) -> { bloc_d'instructions }

أمثلة ذلك

(x) -> x * 2                           #1(x) -> { return x * 2; }               #2(s) -> { System.out.println(s); }   #3() -> 42                                   #4 

الأولى  تستقبل الدالة متغير من نوع int وترجع بقيمة واحدة تلقائيا هي قيمة العملية الحسابية وفي هذه الحالة لا نحتاج لا إلى معقوفتين ولا إلى return

الثانية  مثل الأولى إلا اننا استعملنا المعقوفتين { } وفي هذه الحالة يجب وضع الكلمة return

الثالثة تستقبل arg من نوع string ولا ترجع بشيء يعني هي مثل void

الرابعة لا تستقبل اي arg وترجع بثابت هو 42

 

 

 

استعمالات lambda

 

إحدى أكثر الاستعملات التي ستطبق فيها هي ما رايناه سابقا وستستعمل أيضا بكثرة في 

 

 Listener Lambda

 

 

في الطريقة التقليدية كنا نقوم ب impl للأنترفاس ActionListener عند حدث الضغط على زر (button)

هكذا

JButton greeterButton = new JButton("Click me !");greeterButton.addActionListener(new ActionListener() {    @Override    public void actionPerformed(ActionEvent event) {        JOptionPane.showMessageDialog(null, "Hello !");    }});

ومع lambda صارت هكذا 

JButton greeterButton = new JButton("Click me !");greeterButton.addActionListener( event -> {    JOptionPane.showMessageDialog(null, "Hello !");});

envet هو البراميتر التي تستقبله الدالة |المجهولة lambda

 

 

مراجع

http://viralpatel.net/blogs/lambda-expressions-java-tutorial/

http://blog.zenika.com/index.php?post/2012/05/30/Java-8-et-les-Lambda

تم تعديل بواسطه أحمد أبو عبد البر
2

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

4 إجابة على هذا السؤال .

  • 0

السلام عليكم

 

شكراً أخي أحمد على هذه المقالة المختصرة و المفيدة :)

 

 

أثناء قراءتي للموضوع لفت انتباهي نقطتين اثنتين :

الأولى :

 

الجافا لغة كائنية 100/100 فكل شيء فيها هو كائن

 

 

هل فعلا Java لغة كائنية مائة في المائة ؟

صحيح أنها تتفوق على سي++ في تحديد الـ class كوحدة أساسية لكتابة أي كود جافا (في السي++ يُمكن كتابة كود بسيط على طريقة السي الأم، دون إنشاء class جديد) لكن مع ذلك أعتقد أن لغة Object-Oriented مائة في المائة تقتضي أن تكون كل متغيراتها عبارة عن Objects و كما تعلم في الجافا توجد الـ Primitive Data Types و بالتالي ليس كل متغير في الجافا عبارة عن كائن. طبعاً، توجد الـ Wrapper Classes كحل كائني بديل لكن أعتقد أنه بمجرد وجود متغيرات بالشكل التقليدي يجعل اللغة غير كائنية بشكل تام.

 

الثانية :

في الطريقة التقليدية عندما نريد ان نمرر دالة إلى دالة أخرى كنا نقوم بخطوتين

أولا إنشاء interface يحتوي دالة واحدة  (هي التي ستُمرَر)

ثانيا نقوم ب implimentation  للأنترفاس داخل قوسي الدالة الأم

 

 

أعتقد أن الهدف الأساسي من الواجهة Runnable هو إمكانية استخدام الـ Threads إذا كانت الفئة قد قامت بوراثة فئة مُسبقاً، في هذه الحالة نستخدم الـ implements كبديل لـ extends بما أن الجافا لا تدعم الوراثة المتعددة بشكل مباشر كالذي يوجد في السي++ مثلا.

المثال الذي قدمته أخي أحمد لا أراه مناسباً كتمرير دالة إلى دالة أخرى باستخدام الوسائط لأن الدالة println تم استدعائها داخل جسم الدالة run و هذا شيئ طبيعي يُمكن عمله دون الحاجة إلى عمل implements.

 

أشكرك مرة أخرى على التطرق لموضوع Lambda وهو موضوع ممتع و شيق.

 

 

تحياتي.

1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

أهلا أخي snaker

 

 

 

لكن مع ذلك أعتقد أن لغة Object-Oriented مائة في المائة تقتضي أن تكون كل متغيراتها عبارة عن Objects

المقصود بكونها كائنية انها لا تخرج عن التعامل بالكلاسات والفئات المشتقة منها

 

بخلاف c++ و Object pascal وغيرهما يمكننا أن نعرف متغيرا خارج مجال الكلاسات كما قد وضحت أنت ذلك

 

 

 

 

أعتقد أن الهدف الأساسي من الواجهة Runnable هو إمكانية استخدام الـ Threads إذا كانت الفئة قد قامت بوراثة فئة مُسبقاً، في هذه الحالة نستخدم الـ implements كبديل لـ extends بما أن الجافا لا تدعم الوراثة المتعددة بشكل مباشر كالذي يوجد في السي++ مثلا.

المثال الذي قدمته أخي أحمد لا أراه مناسباً كتمرير دالة إلى دالة أخرى باستخدام الوسائط لأن الدالة println تم استدعائها داخل جسم الدالة run و هذا شيئ طبيعي يُمكن عمله دون الحاجة إلى عمل implements.

كما تعلم أخي فإننا لإنشاء thread نسلك ثلاث طرق

 

الأولى أن نرث من الكلاس Thread وهذه الطريقة المستعملة كثيرا

الثانية أن نقوم ب implimentation للأنترفاس Runnable وهذه المستعملة في Applet لأنها ترث الفئة Applet أو JApplet ولا يمكنها أن ترث الكلاس Thread 

الثالثة هي ان ننشا كائن من نوع Thread يستقبل في بانيه (constrator) كائن آني يقوم ب impli آنية للأنترفاس Runnable وهذه الطريقة هي التي اشرت إليها وجاءت lambda لاستبدالها

 

أنا جئت بمثال بسيط للتوضيح وإلا ففي العمل الحقيقي لا نستدعي الدالة Systam.out.print

 

إليك مثالا حقيقيا 

public class JavaApplication5{      public static void main(String[] args)      {	new Thread(new Runnable()	{	      public void run()	      {		for (int i = 0 ; i < 10 ; i++)		{		      System.out.println("Thread one " + i);		      try		      {			Thread.sleep(1000);		      } catch (InterruptedException ex)		      {			Logger.getLogger(JavaApplication5.class.getName()).log(Level.SEVERE , null , ex);		      }		}	      }	}).start();	new Thread(new Runnable()	{	      public void run()	      {		for (int i = 0 ; i < 10 ; i++)		{		      System.out.println("Thread two " + i);		      try		      {			Thread.sleep(1000);		      } catch (InterruptedException ex)		      {			Logger.getLogger(JavaApplication5.class.getName()).log(Level.SEVERE , null , ex);		      }		}	      }	}).start();      }}

وهذا هو الخرج

Thread one 0Thread two 0Thread one 1Thread two 1Thread one 2Thread two 2Thread one 3Thread two 3Thread one 4Thread two 4Thread one 5Thread two 5Thread one 6Thread two 6Thread one 7Thread two 7Thread one 8Thread two 8Thread one 9Thread two 9
2

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

الأخ أحمد بصدق كلمة رائع قليلة بحق موضوعك , سر على بركة الله في مثل هذه المواضيع الجميلة . 

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

مشاركة طيبة وموضوع رائع...اسعدتني هذه الاضافة

شكرا لك اخي الكريم

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

من فضلك سجل دخول لتتمكن من التعليق

ستتمكن من اضافه تعليقات بعد التسجيل



سجل دخولك الان

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .