عبارات لامبدا

عبارت لامبدا (Lambda expressions) در اصل یک متد بی نام است. این متد ناشناس به تنهایی قابل اجرا نیست و برای پیاده‌سازی متدی که در یک رابط تابعی یا functional interface تعریف‌ شده به کار می‌رود. رابط تابعی، اینترفیسی است که فقط و فقط یک متد در آن تعریف شده است. فرض کنید یک رابط تابعی به صورت زیر داریم :

interface MyMessage 
{
   void ShowMessage(String message);
}

یک راه برای Override کردن متد این رابط استفاده از کلاس های داخلی بی نام به صورت زیر می باشد :

public class MyFirstProgram
{
    interface MyMessage
    {
        void ShowMessage(String message);
    }

    public static void main(String[] args)
    {
        MyMessage m = new MyMessage()              
        {                                          
            @Override                              
            public void ShowMessage(String message)
            {                                      
                System.out.println(message);       
            }                                      
        };                                         

        m.ShowMessage("Hello World!");
    }
}
Hello World!

ولی یک راه ساده تر هم وجود دارد و آن استفاده از عبارات لامبدا است. در کد زیر متد ()ShowMessage با استفاده از عبارات لامبدا پیاده سازی شده است :

public class MyFirstProgram
{
    interface MyMessage
    {
        void ShowMessage(String message);
    }

    public static void main(String[] args)
    {
        MyMessage m = (message) -> System.out.println(message);

        m.ShowMessage("Hello World!");
    }
}
Hello World!

روش کلی استفاده از عبارات لامبدا به صورت زیر است :

parameter -> expression body

در عبارت لامبدا ابتدا پارامترها را بدون ذکر نوعشان می نویسیم و بعد از عملگر -> استفاده می کنیم. سپس دستوراتی را که قرار است اجرا شوند را می نویسیم. نوع پارامترها به صورت خودکار به وسیله کامپایلر تشخیص داده می شود. البته امضاء عبارات لامبدا باید شبیه به امضاء متد باشد. عبارات لامبدا دارای اشکال زیادی هستند. به عنوان مثال در مثال بالا از یک عبارت لامبدایی استفاده کرده ایم که دارای یک دستور ساده اجرایی است. اگر متد شما برای عبارت لامبدا هیچ پارامتری نداشته باشد، همه کاری که لازم است نجام دهید این است که هیچ پارامتری در داخل عبارت لامبدا قرار ندهید :

public class MyFirstProgram
{
    interface MyMessage
    {
        void ShowMessage();
    }

    public static void main(String[] args)
    {
        MyMessage m = () -> System.out.println("Hello World!");

        m.ShowMessage();
    }
}
Hello World!

به این نکته توجه کنید که شما می توانید نوع پارامترهای عبارت لامبدا را نشان دهید.

public class MyFirstProgram
{
    interface MyMessage
    {
        void ShowMessage(String message);
    }

    public static void main(String[] args)
    {
        MyMessage m = (String message) -> System.out.println(message);

        m.ShowMessage("Hello World!");
    }
}
Hello World!

اگر عبارات لامبدای شما دارای چندین دستور اجرایی باشند می توانید آنها را داخل آکولاد قرار دهید. به عبارت لامبدایی که دارای آکولاد باشد بلاک لامبدا می گویند.

public class MyFirstProgram
{
    interface MyMessage
    {
        void ShowMessage(String message);
    }

    public static void main(String[] args)
    {
        MyMessage m = (message) ->                  
        {                                           
            System.out.println(message);            
            System.out.println("Some more message");
        };                                          

        m.ShowMessage("Hello World!");
    }
}
Hello World!
Some more message

در زیر مثالی از یک عبارت لامبدا که دارای مقدار برگشتی است نشان داده شده است :

SampleInterface GetSquare = (number) -> { return (number * number); };

به این نکته توجه کنید که هنگام استفاده از دستور return باید همیشه از دستورات لامبدایی استفاده کنید که دارای آکولاد می باشند. اگر یک عبارت لامبدا فقط دارای یک دستور return ساده باشد می توانید به سادگی آن را به expression lambda تبدیل کنید.

SampleInterface GetSquare = (number) -> (number * number); 

به این نکته توجه کنید که استفاده از پرانتز در کد بالا برای فهم بهتر آن است. اگر یک عبارت لامبدا دارای یک پارامتر ساده و یک دستور return است، می توانید برای سادگی بیشتر پرانتزها را حذف نمایید:

SampleInterface GetSquare = (number) -> number * number; 

عبارت لامبدای بالا دارای دو پارامتر است و حاصل جمع آنها را بر می گرداند.

یک مثال از عبارت لامبدا

می توان عبارات لامبدا را به عنوان آرگومان به دیگر متد ها ارسال کرد. به مثال زیر توجه کنید :

   1: import java.util.Scanner;
   2: import java.text.MessageFormat;
   3: 
   4: public class MyFirstProgram
   5: {
   6:     interface Arithmetic
   7:     {
   8:         int Operation(int x, int y);
   9:     }
  10: 
  11:     public static int GetResult(Arithmetic arithmetic, int num1, int num2)
  12:     {
  13:         return arithmetic.Operation(num1, num2);
  14:     }
  15: 
  16:     public static void main(String[] args)
  17:     {
  18:         Scanner input = new Scanner(System.in);
  19: 
  20:         System.out.print("Enter first number: ");
  21:         int num1 = input.nextInt();
  22:         System.out.print("Enter second number: ");
  23:         int num2 = input.nextInt();
  24: 
  25:         System.out.println(); // Seperator
  26: 
  27:         System.out.println("Sum        = " + GetResult((x, y)->x + y, num1, num2));
  28:         System.out.println("Difference = " + GetResult((x, y)->x - y, num1, num2));
  29:         System.out.println("Product    = " + GetResult((x, y)->x * y, num1, num2));
  30:         System.out.println("Quotient   = " + GetResult((x, y)->x / y, num1, num2));
  31:     }
  32: }
Enter first number: 5
Enter second number: 2

Sum        = 7
Difference = 3
Product    = 10
Quotient   = 2

ابتدا در خط 6 یک رابط ایجاد می کنیم که دارای متدی است که دو آرگومان از نوع اعداد صحیح را قبول کرده و یک مقدار صحیح را بر می گرداند. سپس از این رابط به عنوان یکی از پارامترهای متد ()GetResult استفاده می کنیم(خطوط 14-11). دو پارامتر دیگر، دو عدد هستند که همانطور که خواهیم دید در عملیاتهای مختلف نقش دارند. از آنجاییکه اولین پارامتر یک رابط است، آرگومانی که به آن ارسال می شود باید پیاده سازی متد آن باشد. با استفاده از عبارت لامبدا می توان کدهای خواناتری نوشت و همچنین کدنویسی را کاهش داد. در خطوط 30-27 متد ()GetResult را فراخوانی می کنیم. توجه کنید که متد در هر فراخوانی یک عبارت لامبدا را به عنوان اولین آرگومان قبول می کند.