JavaRush /جاوا بلاگ /Random-UR /جاوا میں لیمبڈا اظہار کے بارے میں مشہور۔ مثالوں اور کاموں...

جاوا میں لیمبڈا اظہار کے بارے میں مشہور۔ مثالوں اور کاموں کے ساتھ۔ حصہ 1

گروپ میں شائع ہوا۔
یہ مضمون کس کے لیے ہے؟
  • ان لوگوں کے لیے جو سوچتے ہیں کہ وہ جاوا کور کو پہلے ہی اچھی طرح جانتے ہیں، لیکن جاوا میں لیمبڈا اظہار کے بارے میں کوئی اندازہ نہیں ہے۔ یا، شاید، آپ نے پہلے ہی لیمبڈاس کے بارے میں کچھ سنا ہے، لیکن تفصیلات کے بغیر۔
  • ان لوگوں کے لیے جو لیمبڈا کے تاثرات کی کچھ سمجھ رکھتے ہیں، لیکن پھر بھی ان کے استعمال سے خوفزدہ اور غیر معمولی ہیں۔
اگر آپ ان میں سے کسی ایک زمرے میں نہیں آتے ہیں، تو آپ کو یہ مضمون بورنگ، غلط اور عام طور پر "ٹھنڈا نہیں" لگے گا۔ اس معاملے میں، یا تو بلا جھجھک گزریں، یا، اگر آپ کو موضوع سے اچھی طرح واقفیت ہے، تو تبصرے میں تجویز کریں کہ میں مضمون کو کس طرح بہتر یا اضافی بنا سکتا ہوں۔ مواد کسی علمی قدر کا دعویٰ نہیں کرتا، بہت کم نیاپن۔ بلکہ، اس کے برعکس: اس میں میں پیچیدہ (کچھ کے لیے) چیزوں کو جتنا آسان ہو سکے بیان کرنے کی کوشش کروں گا۔ مجھے اسٹریم اے پی آئی کی وضاحت کرنے کی درخواست سے لکھنے کی ترغیب ملی۔ میں نے اس کے بارے میں سوچا اور فیصلہ کیا کہ لیمبڈا کے تاثرات کو سمجھے بغیر، "اسٹریمز" کے بارے میں میری کچھ مثالیں ناقابل فہم ہوں گی۔ تو آئیے لیمبڈاس کے ساتھ شروع کریں۔ جاوا میں لیمبڈا اظہار کے بارے میں مشہور۔  مثالوں اور کاموں کے ساتھ۔  حصہ 1 - 1اس مضمون کو سمجھنے کے لیے کس علم کی ضرورت ہے:
  1. آبجیکٹ پر مبنی پروگرامنگ کی تفہیم (اس کے بعد OOP کہا جاتا ہے)، یعنی:
    • کلاس اور اشیاء کیا ہیں، ان میں کیا فرق ہے اس کا علم؛
    • اس بات کا علم کہ انٹرفیس کیا ہیں، وہ کلاسوں سے کیسے مختلف ہیں، ان کے درمیان کیا تعلق ہے (انٹرفیس اور کلاسز)؛
    • اس بات کا علم کہ طریقہ کیا ہے، اسے کیسے پکارا جائے، تجریدی طریقہ کیا ہے (یا بغیر نفاذ کے طریقہ)، طریقہ کار کے پیرامیٹرز/دلائل کیا ہیں، انہیں وہاں کیسے منتقل کیا جائے؛
    • رسائی میں ترمیم کرنے والے، جامد طریقے/متغیر، حتمی طریقے/متغیر؛
    • وراثت (کلاسز، انٹرفیس، انٹرفیس کی متعدد وراثت)۔
  2. جاوا کور کا علم: جنرک، مجموعے (فہرستیں)، تھریڈز۔
ٹھیک ہے، چلو شروع کرتے ہیں۔

ایک چھوٹی سی تاریخ

لیمبڈا کے تاثرات جاوا میں فنکشنل پروگرامنگ سے آئے، اور وہاں ریاضی سے۔ امریکہ میں 20ویں صدی کے وسط میں، پرنسٹن یونیورسٹی میں ایک مخصوص الونزو چرچ کام کرتا تھا، جسے ریاضی اور ہر قسم کے تجرید کا بہت شوق تھا۔ یہ الونزو چرچ تھا جو لیمبڈا کیلکولس کے ساتھ آیا تھا، جو پہلے کچھ تجریدی خیالات کا مجموعہ تھا اور اس کا پروگرامنگ سے کوئی تعلق نہیں تھا۔ اسی وقت، ایلن ٹیورنگ اور جان وون نیومن جیسے ریاضی دان اسی پرنسٹن یونیورسٹی میں کام کرتے تھے۔ سب کچھ ایک ساتھ آیا: چرچ لیمبڈا کیلکولس سسٹم کے ساتھ آیا، ٹورنگ نے اپنی تجریدی کمپیوٹنگ مشین تیار کی، جسے اب "Turing مشین" کہا جاتا ہے۔ ٹھیک ہے، وان نیومن نے کمپیوٹرز کے فن تعمیر کا ایک خاکہ تجویز کیا، جس نے جدید کمپیوٹرز کی بنیاد بنائی (اور اب اسے "وان نیومن فن تعمیر" کہا جاتا ہے)۔ اس وقت، الونزو چرچ کے خیالات نے اتنی شہرت حاصل نہیں کی تھی جتنی ان کے ساتھیوں کے کام نے ("خالص" ریاضی کے شعبے کو چھوڑ کر)۔ تاہم، تھوڑی دیر بعد، ایک مخصوص جان میکارتھی (کہانی کے وقت پرنسٹن یونیورسٹی کا گریجویٹ بھی تھا - میساچوسٹس انسٹی ٹیوٹ آف ٹیکنالوجی کا ملازم) چرچ کے خیالات میں دلچسپی لینے لگا۔ ان کی بنیاد پر، 1958 میں اس نے پہلی فنکشنل پروگرامنگ لینگویج Lisp بنائی۔ اور 58 سال بعد، فنکشنل پروگرامنگ کے آئیڈیاز جاوا میں نمبر 8 کے طور پر لیک ہوئے۔ 70 سال بھی نہیں گزرے... درحقیقت، ریاضیاتی آئیڈیا کو عملی طور پر لاگو کرنے کے لیے یہ سب سے طویل عرصہ نہیں ہے۔

جوہر

ایک لیمبڈا اظہار ایک ایسا فنکشن ہے۔ آپ اسے جاوا میں ایک باقاعدہ طریقہ کے طور پر سوچ سکتے ہیں، فرق صرف اتنا ہے کہ اسے دلیل کے طور پر دوسرے طریقوں تک بھیجا جا سکتا ہے۔ ہاں، نہ صرف نمبروں، تاروں اور بلیوں کو طریقوں سے منتقل کرنا ممکن ہو گیا ہے، بلکہ دوسرے طریقے بھی! ہمیں اس کی کب ضرورت ہو سکتی ہے؟ مثال کے طور پر، اگر ہم کچھ کال بیک پاس کرنا چاہتے ہیں۔ ہمیں اس طریقہ کی ضرورت ہے جسے ہم کہتے ہیں کسی دوسرے طریقے کو کال کرنے کے قابل ہونے کے لئے جسے ہم اس تک پہنچاتے ہیں۔ یعنی، تاکہ ہمارے پاس کچھ معاملات میں ایک کال بیک اور دوسروں میں دوسری کو منتقل کرنے کا موقع ہو۔ اور ہمارا طریقہ، جو ہماری کال بیکس کو قبول کرے گا، انہیں کال کرے گا۔ ایک سادہ سی مثال ترتیب دینا ہے۔ ہم کہتے ہیں کہ ہم کچھ اس طرح کی مشکل چھانٹی لکھتے ہیں جو کچھ اس طرح نظر آتی ہے:
public void mySuperSort() {
    // ... do something here
    if(compare(obj1, obj2) > 0)
    // ... and here we do something
}
جہاں، ifہم طریقہ کو کہتے ہیں compare()، وہاں دو اشیاء کو پاس کرتے ہیں جن کا ہم موازنہ کرتے ہیں، اور ہم یہ جاننا چاہتے ہیں کہ ان میں سے کون سی چیز "زیادہ" ہے۔ ہم "زیادہ" کو "چھوٹا" سے پہلے رکھیں گے۔ میں نے اقتباسات میں "زیادہ" لکھا کیونکہ ہم ایک آفاقی طریقہ لکھ رہے ہیں جو نہ صرف صعودی میں بلکہ نزولی ترتیب میں بھی ترتیب دے سکے گا (اس صورت میں، "زیادہ" وہ شے ہوگی جو بنیادی طور پر چھوٹی ہوگی، اور اس کے برعکس) . اس اصول کو ترتیب دینے کے لیے کہ ہم کس طرح ترتیب دینا چاہتے ہیں، ہمیں اسے کسی نہ کسی طرح اپنے پر منتقل کرنے کی ضرورت ہے mySuperSort()۔ اس صورت میں، ہم اپنے طریقہ کو بلانے کے دوران کسی نہ کسی طرح "کنٹرول" کرنے کے قابل ہو جائیں گے۔ یقیناً، آپ صعودی اور نزولی ترتیب میں ترتیب دینے mySuperSortAsc()کے لیے دو الگ الگ طریقے لکھ سکتے ہیں۔ mySuperSortDesc()یا طریقہ کے اندر کچھ پیرامیٹر پاس کریں (مثال کے طور پر، booleanاگر true، صعودی ترتیب میں ترتیب دیں، اور اگر falseنزولی ترتیب میں)۔ لیکن کیا ہوگا اگر ہم کچھ سادہ ڈھانچے کو نہیں چھانٹنا چاہتے ہیں، بلکہ، مثال کے طور پر، سٹرنگ اریوں کی فہرست؟ ہمارے طریقہ کار کو کیسے mySuperSort()معلوم ہوگا کہ ان سٹرنگ اریوں کو کیسے ترتیب دیا جائے؟ سائز کرنے کے لئے؟ الفاظ کی کل لمبائی سے؟ شاید حروف تہجی کے لحاظ سے، صف میں پہلی قطار پر منحصر ہے؟ لیکن کیا ہوگا اگر، کچھ معاملات میں، ہمیں صفوں کی فہرست کو صف کے سائز کے مطابق ترتیب دینے کی ضرورت ہے، اور دوسری صورت میں، صف میں الفاظ کی کل لمبائی کے حساب سے؟ میرا خیال ہے کہ آپ نے موازنہ کرنے والوں کے بارے میں پہلے ہی سنا ہے اور یہ کہ ایسی صورتوں میں ہم صرف اپنے چھانٹنے کے طریقہ کار پر ایک موازنہ کرنے والے اعتراض کو منتقل کرتے ہیں، جس میں ہم ان اصولوں کو بیان کرتے ہیں جن کے ذریعے ہم ترتیب دینا چاہتے ہیں۔ چونکہ معیاری طریقہ sort()اسی اصول پر لاگو ہوتا ہے، mySuperSort()مثالوں میں میں معیاری طریقہ استعمال کروں گا sort()۔
String[] array1 = {"Mother", "soap", "frame"};
String[] array2 = {"I", "Very", "I love", "java"};
String[] array3 = {"world", "work", "May"};

List<String[]> arrays = new ArrayList<>();
arrays.add(array1);
arrays.add(array2);
arrays.add(array3);

Comparator<String[]> sortByLength = new Comparator<String[]>() {
    @Override
    public int compare(String[] o1, String[] o2) {
        return o1.length - o2.length;
    }
};

Comparator<String[]> sortByWordsLength = new Comparator<String[]>() {
    @Override
    public int compare(String[] o1, String[] o2) {
        int length1 = 0;
        int length2 = 0;
        for (String s : o1) {
            length1 += s.length();
        }
        for (String s : o2) {
            length2 += s.length();
        }
        return length1 - length2;
    }
};

arrays.sort(sortByLength);
نتیجہ:
  1. ماں نے فریم دھویا
  2. امن لیبر مئی
  3. مجھے واقعی جاوا پسند ہے۔
یہاں صفوں کو ہر صف میں الفاظ کی تعداد کے حساب سے ترتیب دیا گیا ہے۔ کم الفاظ والی صف کو "چھوٹا" سمجھا جاتا ہے۔ اس لیے یہ شروع میں آتا ہے۔ جہاں زیادہ الفاظ ہوتے ہیں اسے "زیادہ" سمجھا جاتا ہے اور آخر میں ختم ہوتا ہے۔ اگر sort()ہم کسی دوسرے موازنہ کو طریقہ سے پاس کرتے ہیں (sortByWordsLength)، تو نتیجہ مختلف ہوگا:
  1. امن لیبر مئی
  2. ماں نے فریم دھویا
  3. مجھے واقعی جاوا پسند ہے۔
اب ایسی صفوں کے الفاظ میں اریوں کو کل حروف کی تعداد کے حساب سے ترتیب دیا گیا ہے۔ پہلی صورت میں 10 حروف ہیں، دوسرے میں 12، اور تیسرے میں 15۔ اگر ہم صرف ایک کمپیریٹر استعمال کرتے ہیں، تو ہم اس کے لیے الگ متغیر نہیں بنا سکتے، بلکہ صرف ایک گمنام کلاس کی ایک چیز بنا سکتے ہیں۔ طریقہ کال کرنے کا sort()وقت اس کی طرح:
String[] array1 = {"Mother", "soap", "frame"};
String[] array2 = {"I", "Very", "I love", "java"};
String[] array3 = {"world", "work", "May"};

List<String[]> arrays = new ArrayList<>();
arrays.add(array1);
arrays.add(array2);
arrays.add(array3);

arrays.sort(new Comparator<String[]>() {
    @Override
    public int compare(String[] o1, String[] o2) {
        return o1.length - o2.length;
    }
});
نتیجہ وہی ہوگا جو پہلی صورت میں آیا تھا۔ ٹاسک 1 اس مثال کو دوبارہ لکھیں تاکہ یہ صفوں کو صف میں الفاظ کی تعداد کے صعودی ترتیب میں نہیں بلکہ نزولی ترتیب میں ترتیب دے۔ یہ سب ہم پہلے ہی جانتے ہیں۔ ہم چیزوں کو طریقوں میں منتقل کرنے کا طریقہ جانتے ہیں، ہم اس یا اس اعتراض کو کسی طریقہ پر منتقل کر سکتے ہیں اس پر منحصر ہے کہ ہمیں اس وقت کیا ضرورت ہے، اور اس طریقہ کے اندر جہاں ہم ایسی چیز کو پاس کرتے ہیں، وہ طریقہ جس کے لیے ہم نے عمل درآمد لکھا ہے اسے کہا جائے گا۔ . سوال یہ پیدا ہوتا ہے: لیمبڈا اظہار کا اس سے کیا تعلق ہے؟ یہ دیکھتے ہوئے کہ لیمبڈا ایک ایسی چیز ہے جس میں بالکل ایک طریقہ ہوتا ہے۔ یہ ایک طریقہ آبجیکٹ کی طرح ہے۔ کسی چیز میں لپٹا ہوا طریقہ۔ ان کے پاس تھوڑا سا غیر معمولی نحو ہے (لیکن اس پر بعد میں مزید)۔ آئیے اس اندراج پر ایک اور نظر ڈالتے ہیں۔
arrays.sort(new Comparator<String[]>() {
    @Override
    public int compare(String[] o1, String[] o2) {
        return o1.length - o2.length;
    }
});
یہاں ہم اپنی فہرست لیتے ہیں arraysاور اس کے طریقہ کار کو کہتے ہیں sort()، جہاں ہم ایک ہی طریقہ کے ساتھ موازنہ کرنے والے آبجیکٹ کو پاس کرتے ہیں compare()(اس سے ہمارے لیے کوئی فرق نہیں پڑتا کہ اسے کیا کہتے ہیں، کیونکہ اس چیز میں یہ واحد ہے، ہم اسے یاد نہیں کریں گے)۔ یہ طریقہ دو پیرامیٹرز لیتا ہے، جس کے ساتھ ہم اگلے کام کرتے ہیں۔ اگر آپ IntelliJ IDEA میں کام کرتے ہیں ، تو آپ نے شاید دیکھا ہوگا کہ یہ آپ کو یہ کوڈ نمایاں طور پر مختصر کرنے کے لیے کس طرح پیش کرتا ہے:
arrays.sort((o1, o2) -> o1.length - o2.length);
اس طرح چھ لائنیں ایک مختصر میں بدل گئیں۔ 6 لائنوں کو ایک مختصر میں دوبارہ لکھا گیا۔ کچھ غائب ہو گیا ہے، لیکن میں اس بات کی ضمانت دیتا ہوں کہ کوئی اہم چیز غائب نہیں ہوئی ہے، اور یہ کوڈ بالکل اسی طرح کام کرے گا جیسا کہ کسی گمنام کلاس کے ساتھ ہوتا ہے۔ ٹاسک 2 لیمبڈاس کا استعمال کرتے ہوئے مسئلہ 1 کے حل کو دوبارہ لکھنے کا طریقہ معلوم کریں (آخری حربے کے طور پر، IntelliJ IDEA سے اپنی گمنام کلاس کو لیمبڈا میں تبدیل کرنے کے لیے کہیں)۔

آئیے انٹرفیس کے بارے میں بات کرتے ہیں۔

بنیادی طور پر، ایک انٹرفیس صرف تجریدی طریقوں کی ایک فہرست ہے۔ جب ہم ایک کلاس بناتے ہیں اور کہتے ہیں کہ یہ کسی قسم کے انٹرفیس کو نافذ کرے گا، تو ہمیں اپنی کلاس میں ان طریقوں کا نفاذ لکھنا چاہیے جو انٹرفیس میں درج ہیں (یا، آخری حربے کے طور پر، اسے نہ لکھیں، بلکہ کلاس کو خلاصہ بنائیں۔ )۔ بہت سے مختلف طریقوں کے ساتھ انٹرفیس ہیں (مثال کے طور پر List)، صرف ایک طریقہ کے ساتھ انٹرفیس ہیں (مثال کے طور پر، ایک ہی Comparator یا Runnable)۔ بغیر کسی ایک طریقہ کے انٹرفیس ہیں (نام نہاد مارکر انٹرفیس، مثال کے طور پر سیریلائز ایبل)۔ وہ انٹرفیس جن کا صرف ایک طریقہ ہے انہیں فنکشنل انٹرفیس بھی کہا جاتا ہے ۔ جاوا 8 میں انہیں ایک خصوصی @FunctionalInterface تشریح کے ساتھ نشان زد کیا گیا ہے ۔ یہ ایک واحد طریقہ کے ساتھ انٹرفیس ہے جو لیمبڈا اظہار کے استعمال کے لیے موزوں ہے۔ جیسا کہ میں نے اوپر کہا، ایک لیمبڈا اظہار ایک ایسا طریقہ ہے جو کسی چیز میں لپٹا ہوا ہے۔ اور جب ہم کسی ایسی چیز کو کہیں سے پاس کرتے ہیں تو درحقیقت ہم اس ایک ہی طریقہ کو پاس کرتے ہیں۔ یہ پتہ چلتا ہے کہ ہمیں اس سے کوئی فرق نہیں پڑتا ہے کہ اس طریقہ کو کیا کہا جاتا ہے۔ ہمارے لیے جو کچھ اہم ہے وہ پیرامیٹرز ہیں جو یہ طریقہ اختیار کرتا ہے، اور درحقیقت، طریقہ کار کوڈ ہی۔ ایک لیمبڈا اظہار ہے، بنیادی طور پر۔ ایک فنکشنل انٹرفیس کا نفاذ۔ جہاں ہم ایک طریقہ کے ساتھ انٹرفیس دیکھتے ہیں، اس کا مطلب ہے کہ ہم لیمبڈا کا استعمال کرتے ہوئے ایسی گمنام کلاس کو دوبارہ لکھ سکتے ہیں۔ اگر انٹرفیس میں ایک سے زیادہ/کم طریقہ ہے، تو لیمبڈا اظہار ہمارے مطابق نہیں ہوگا، اور ہم ایک گمنام کلاس، یا یہاں تک کہ ایک باقاعدہ استعمال کریں گے۔ یہ لیمبڈاس میں کھودنے کا وقت ہے۔ :)

نحو

عمومی ترکیب کچھ اس طرح ہے:
(параметры) -> {тело метода}
یعنی قوسین، ان کے اندر طریقہ کار کے پیرامیٹرز ہیں، ایک "تیر" (یہ ایک قطار میں دو حروف ہیں: مائنس اور اس سے بڑا)، جس کے بعد طریقہ کار کا باڈی ہمیشہ کی طرح گھوبگھرالی منحنی خطوط وحدانی میں ہے۔ طریقہ کار کی وضاحت کرتے وقت پیرامیٹرز انٹرفیس میں بیان کردہ ان سے مطابقت رکھتے ہیں۔ اگر متغیرات کی قسم کو کمپائلر کے ذریعہ واضح طور پر بیان کیا جاسکتا ہے (ہمارے معاملے میں، یہ یقینی طور پر جانا جاتا ہے کہ ہم سٹرنگز کی صفوں کے ساتھ کام کر رہے ہیں، کیونکہ یہ Listسٹرنگز کی صفوں کے ذریعے بالکل ٹھیک ٹائپ کیا جاتا ہے)، پھر متغیر کی قسم کی String[]ضرورت نہیں ہے۔ لکھا جائے
اگر آپ کو یقین نہیں ہے تو، قسم کی وضاحت کریں، اور اگر ضرورت نہ ہو تو IDEA اسے بھوری رنگ میں نمایاں کرے گا۔
مثال کے طور پر آپ اوریکل ٹیوٹوریل میں مزید پڑھ سکتے ہیں ۔ اسے "ٹارگٹ ٹائپنگ" کہا جاتا ہے ۔ متغیرات کو کوئی بھی نام دیا جا سکتا ہے، ضروری نہیں کہ وہ انٹرفیس میں مخصوص ہوں۔ اگر کوئی پیرامیٹرز نہیں ہیں، تو صرف قوسین۔ اگر صرف ایک پیرامیٹر ہے تو صرف متغیر کا نام قوسین کے بغیر۔ ہم نے پیرامیٹرز کو ترتیب دیا ہے، اب خود لیمبڈا اظہار کے جسم کے بارے میں۔ گھوبگھرالی منحنی خطوط وحدانی کے اندر، کوڈ کو باقاعدہ طریقہ کے طور پر لکھیں۔ اگر آپ کا پورا کوڈ صرف ایک لائن پر مشتمل ہے، تو آپ کو گھنگھریالے منحنی خطوط وحدانی بالکل نہیں لکھنا پڑے گا (جیسا کہ ifs اور loops کے ساتھ)۔ اگر آپ کا لیمبڈا کچھ واپس کرتا ہے، لیکن اس کا جسم ایک لائن پر مشتمل ہے، تو اسے returnلکھنا بالکل ضروری نہیں ہے۔ لیکن اگر آپ کے پاس گھوبگھرالی منحنی خطوط وحدانی ہے، تو، عام طریقہ کی طرح، آپ کو واضح طور پر لکھنے کی ضرورت ہے return۔

مثالیں

مثال 1۔
() -> {}
آسان ترین آپشن۔ اور سب سے بے معنی :) کیونکہ اس سے کچھ نہیں ہوتا۔ مثال 2۔
() -> ""
یہ بھی ایک دلچسپ آپشن ہے۔ یہ کچھ بھی قبول نہیں کرتا اور ایک خالی تار واپس کرتا ہے ( returnغیر ضروری کے طور پر چھوڑ دیا گیا)۔ وہی، لیکن اس کے ساتھ return:
() -> {
    return "";
}
مثال 3۔ ہیلو ورلڈ لیمبڈاس کا استعمال کرتے ہوئے
() -> System.out.println("Hello world!")
کچھ وصول نہیں کرتا، کچھ بھی نہیں لوٹاتا (ہم returnکال سے پہلے نہیں ڈال سکتے System.out.println()، کیونکہ طریقہ کار میں واپسی کی قسم println() — void)، صرف اسکرین پر ایک نوشتہ دکھاتی ہے۔ انٹرفیس کو نافذ کرنے کے لیے مثالی ہے Runnable۔ یہی مثال زیادہ مکمل ہے:
public class Main {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("Hello world!")).start();
    }
}
یا اس طرح:
public class Main {
    public static void main(String[] args) {
        Thread t = new Thread(() -> System.out.println("Hello world!"));
        t.start();
    }
}
یا ہم لامبڈا ایکسپریشن کو کسی شے کے طور پر محفوظ کر سکتے ہیں type Runnable، اور پھر اسے کنسٹرکٹر کو دے سکتے ہیں thread’а:
public class Main {
    public static void main(String[] args) {
        Runnable runnable = () -> System.out.println("Hello world!");
        Thread t = new Thread(runnable);
        t.start();
    }
}
آئیے لیمبڈا اظہار کو متغیر میں محفوظ کرنے کے لمحے پر گہری نظر ڈالیں۔ انٹرفیس Runnableہمیں بتاتا ہے کہ اس کی اشیاء کا ایک طریقہ ہونا چاہیے public void run()۔ انٹرفیس کے مطابق، رن کا طریقہ کسی بھی چیز کو پیرامیٹرز کے طور پر قبول نہیں کرتا ہے۔ اور یہ کچھ بھی واپس نہیں کرتا ہے (void)۔ لہٰذا اس طرح لکھتے وقت کسی نہ کسی طریقے سے ایک ایسی چیز بنائی جائے گی جو نہ کسی چیز کو قبول کرے اور نہ ہی واپس کرے۔ run()جو انٹرفیس کے طریقہ کار سے بالکل مطابقت رکھتا ہے Runnable۔ یہی وجہ ہے کہ ہم اس لیمبڈا اظہار کو متغیر میں ڈالنے کے قابل تھے جیسے Runnable. مثال 4
() -> 42
ایک بار پھر، یہ کچھ بھی قبول نہیں کرتا ہے، لیکن نمبر 42 لوٹاتا ہے۔ یہ lambda اظہار قسم کے متغیر میں رکھا جا سکتا ہے Callable، کیونکہ یہ انٹرفیس صرف ایک طریقہ کی وضاحت کرتا ہے، جو کچھ اس طرح لگتا ہے:
V call(),
Vواپسی کی قیمت کی قسم کہاں ہے (ہمارے معاملے میں int)۔ اس کے مطابق، ہم اس طرح کے لیمبڈا اظہار کو مندرجہ ذیل طور پر ذخیرہ کرسکتے ہیں:
Callable<Integer> c = () -> 42;
مثال 5. کئی سطروں میں لیمبڈا
() -> {
    String[] helloWorld = {"Hello", "world!"};
    System.out.println(helloWorld[0]);
    System.out.println(helloWorld[1]);
}
ایک بار پھر، یہ پیرامیٹرز اور اس کی واپسی کی قسم کے بغیر لیمبڈا اظہار ہے void(چونکہ کوئی نہیں ہے returnمثال 6
x -> x
یہاں ہم کسی چیز کو متغیر میں لیتے ہیں хاور اسے واپس کرتے ہیں۔ براہ کرم نوٹ کریں کہ اگر صرف ایک پیرامیٹر کو قبول کیا جائے تو اس کے ارد گرد قوسین لکھنے کی ضرورت نہیں ہے۔ وہی، لیکن بریکٹ کے ساتھ:
(x) -> x
اور یہاں ایک واضح کے ساتھ آپشن ہے return:
x -> {
    return x;
}
یا اس طرح، بریکٹ کے ساتھ اور return:
(x) -> {
    return x;
}
یا قسم کے واضح اشارے کے ساتھ (اور، اس کے مطابق، قوسین کے ساتھ):
(int x) -> x
مثال 7
x -> ++x
ہم اسے قبول کرتے ہیں хاور اسے واپس کرتے ہیں، لیکن 1مزید کے لیے۔ آپ اسے اس طرح بھی دوبارہ لکھ سکتے ہیں:
x -> x + 1
دونوں صورتوں میں، ہم پیرامیٹر، میتھڈ باڈی، اور لفظ کے ارد گرد قوسین کی نشاندہی نہیں کرتے return، کیونکہ یہ ضروری نہیں ہے۔ بریکٹ اور واپسی والے اختیارات مثال 6 میں بیان کیے گئے ہیں۔ مثال 8
(x, y) -> x % y
ہم کچھ کو قبول کرتے ہیں хاور уبقیہ تقسیم xکو واپس کر دیتے ہیں y۔ پیرامیٹرز کے ارد گرد قوسین پہلے ہی یہاں درکار ہیں۔ وہ صرف اس وقت اختیاری ہیں جب صرف ایک پیرامیٹر ہو۔ اس طرح کی اقسام کے واضح اشارے کے ساتھ:
(double x, int y) -> x % y
مثال 9
(Cat cat, String name, int age) -> {
    cat.setName(name);
    cat.setAge(age);
}
ہم ایک کیٹ آبجیکٹ، نام کے ساتھ ایک تار اور ایک عدد عدد کو قبول کرتے ہیں۔ خود طریقہ کار میں، ہم نے بلی کا نام اور عمر مقرر کی ہے۔ catچونکہ ہمارا متغیر ایک حوالہ کی قسم ہے، لہٰذا لیمبڈا ایکسپریشن کے باہر کیٹ آبجیکٹ بدل جائے گا (اسے اندر سے گزرے ہوئے نام اور عمر ملے گی)۔ تھوڑا زیادہ پیچیدہ ورژن جو اسی طرح کے لیمبڈا کا استعمال کرتا ہے:
public class Main {
    public static void main(String[] args) {
        // create a cat and print to the screen to make sure it's "blank"
        Cat myCat = new Cat();
        System.out.println(myCat);

        // create lambda
        Settable<Cat> s = (obj, name, age) -> {
            obj.setName(name);
            obj.setAge(age);
        };

        // call the method, to which we pass the cat and the lambda
        changeEntity(myCat, s);
        // display on the screen and see that the state of the cat has changed (has a name and age)
        System.out.println(myCat);
    }

    private static <T extends WithNameAndAge>  void changeEntity(T entity, Settable<T> s) {
        s.set(entity, "Murzik", 3);
    }
}

interface WithNameAndAge {
    void setName(String name);
    void setAge(int age);
}

interface Settable<C extends WithNameAndAge> {
    void set(C entity, String name, int age);
}

class Cat implements WithNameAndAge {
    private String name;
    private int age;

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
نتیجہ: بلی{name='null', age=0} Cat{name='Murzik', age=3} جیسا کہ آپ دیکھ سکتے ہیں، پہلے بلی کی چیز کی ایک حالت تھی، لیکن لیمبڈا اظہار استعمال کرنے کے بعد، حالت بدل گئی۔ . لیمبڈا کے تاثرات جنرک کے ساتھ اچھی طرح کام کرتے ہیں۔ اور اگر ہمیں ایک کلاس بنانے کی ضرورت ہے Dog، مثال کے طور پر، یہ بھی لاگو کرے گا WithNameAndAge، تو پھر طریقہ کار میں main()ہم Dog کے ساتھ وہی آپریشن کر سکتے ہیں، بغیر لیمبڈا اظہار کو بالکل تبدیل کیے بغیر۔ ٹاسک 3 ایک فنکشنل انٹرفیس کو اس طریقہ کے ساتھ لکھیں جو ایک نمبر لیتا ہے اور بولین ویلیو دیتا ہے۔ اس طرح کے انٹرفیس کا نفاذ ایک لیمبڈا ایکسپریشن کی شکل میں لکھیں جو واپس آتا ہے trueاگر پاس شدہ نمبر کو بغیر کسی بقیہ کے 13 سے تقسیم کیا جائے تو ٹاسک 4 ۔ ایک فنکشنل انٹرفیس کو ایک طریقہ کے ساتھ لکھیں جو دو سٹرنگ لے اور ایک ہی سٹرنگ واپس کرے۔ اس طرح کے انٹرفیس کا نفاذ لیمبڈا کی شکل میں لکھیں جو سب سے لمبی تار کو لوٹاتا ہے۔ ٹاسک 5 ایک ایسے طریقہ کے ساتھ ایک فنکشنل انٹرفیس لکھیں جو تین فرکشنل نمبرز کو قبول کرتا ہے: a, b, cاور وہی فریکشنل نمبر لوٹاتا ہے۔ اس طرح کے انٹرفیس کا نفاذ ایک لیمبڈا اظہار کی شکل میں لکھیں جو امتیازی سلوک کو لوٹاتا ہے۔ کون بھول گیا، D = b^2 - 4ac ۔ ٹاسک 6 ۔ ٹاسک 5 سے فنکشنل انٹرفیس کا استعمال کرتے ہوئے، ایک لیمبڈا ایکسپریشن لکھیں جو آپریشن کا نتیجہ واپس کرتا ہے a * b^c۔ جاوا میں لیمبڈا اظہار کے بارے میں مشہور۔ مثالوں اور کاموں کے ساتھ۔ حصہ 2.
تبصرے
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION