CodeGym /جاوا بلاگ /Random-SD /جاوا ۾ lambda اظهار جي وضاحت. مثالن ۽ ڪمن سان. حصو 2
John Squirrels
سطح
San Francisco

جاوا ۾ lambda اظهار جي وضاحت. مثالن ۽ ڪمن سان. حصو 2

گروپ ۾ شايع ٿيل
هي مضمون ڪنهن لاءِ آهي؟
  • اھو انھن ماڻھن لاءِ آھي جيڪي ھن مضمون جو پھريون حصو پڙھندا آھن ؛
  • اهو انهن ماڻهن لاءِ آهي جيڪي سمجهن ٿا ته اهي اڳ ۾ ئي جاوا ڪور کي چڱي طرح ڄاڻن ٿا، پر جاوا ۾ ليمبڊا جي اظهار بابت ڪا ڄاڻ ناهي. يا ٿي سگهي ٿو ته انهن لامبڊا جي اظهار بابت ڪجهه ٻڌو آهي، پر تفصيل نه آهي.
  • اهو انهن ماڻهن لاءِ آهي جن کي ليمبڊا جي اظهار جي هڪ خاص سمجهه آهي، پر اڃا تائين انهن کان ڊڄي ويا آهن ۽ انهن کي استعمال ڪرڻ جي عادي ناهي.
جيڪڏهن توهان انهن مان ڪنهن به قسم جي قابل نه آهيو، توهان شايد هي مضمون بورنگ، غلط، يا عام طور تي توهان جي چانهه جو پيالو نه ڳولي سگهو ٿا. انهي حالت ۾، ٻين شين ڏانهن وڃڻ لاء آزاد محسوس ڪريو، يا، جيڪڏهن توهان مضمون ۾ چڱي طرح ڄاڻو ٿا، مهرباني ڪري تبصرن ۾ تجويز ڏيو ته آئون آرٽيڪل کي بهتر يا اضافي ڪري سگهان ٿو. جاوا ۾ lambda اظهار جي وضاحت.  مثالن ۽ ڪمن سان.  حصو 2 - 1مواد ڪنهن به علمي قدر جي دعويٰ نٿو ڪري، اڪيلو ڇڏي ڏيو نوانيت. بلڪل برعڪس: مان ڪوشش ڪندس ته انهن شين کي بيان ڪرڻ جي ڪوشش ڪندس جيڪي پيچيده آهن (ڪجهه ماڻهن لاءِ) جيترو ٿي سگهي. اسٽريم API جي وضاحت ڪرڻ لاءِ هڪ درخواست مون کي هن لکڻ لاءِ متاثر ڪيو. مون ان جي باري ۾ سوچيو ۽ فيصلو ڪيو ته منهنجي وهڪري جا ڪجهه مثال ليمبڊا اظهار جي سمجھڻ کان سواءِ سمجھ ۾ نه ايندا. تنهنڪري اسان شروع ڪنداسين lambda اظهار سان.

خارجي متغيرات تائين رسائي

ڇا هي ڪوڊ هڪ گمنام طبقي سان گڏ آهي؟
int counter = 0;
Runnable r = new Runnable() {

    @Override
    public void run() {
        counter++;
    }
};
نه. counter متغير هجڻ لازمي آهي final. يا جيڪڏهن نه final، ته پوءِ گهٽ ۾ گهٽ اهو ان جو قدر تبديل نٿو ڪري سگهي. ساڳيو اصول lambda اظهار ۾ لاڳو ٿئي ٿو. اهي سڀئي متغير تائين رسائي ڪري سگهن ٿا جيڪي اهي "ڏس" ڪري سگهن ٿا جڳه کان اهي اعلان ڪيا ويا آهن. پر هڪ ليمبڊا انهن کي تبديل نه ڪرڻ گهرجي (انهن کي نئين قيمت تفويض). تنهن هوندي، گمنام طبقن ۾ هن پابندي کي نظرانداز ڪرڻ جو هڪ طريقو آهي. بس هڪ حوالو متغير ٺاهيو ۽ اعتراض جي اندروني حالت کي تبديل ڪريو. ائين ڪرڻ ۾، متغير پاڻ کي تبديل نٿو ڪري (ساڳئي اعتراض ڏانهن اشارو ڪري ٿو) ۽ محفوظ طور تي نشان لڳل ڪري سگهجي ٿو final.
final AtomicInteger counter = new AtomicInteger(0);
Runnable r = new Runnable() {

    @Override
    public void run() {
        counter.incrementAndGet();
    }
};
هتي اسان جو counterمتغير هڪ اعتراض جو حوالو آهي AtomicInteger. ۽ incrementAndGet()طريقو هن اعتراض جي حالت کي تبديل ڪرڻ لاء استعمال ڪيو ويندو آهي. متغير جو قدر پاڻ کي تبديل نٿو ڪري جڏهن پروگرام هلندي آهي. اهو هميشه ساڳئي اعتراض ڏانهن اشارو ڪري ٿو، جيڪو اسان کي حتمي لفظ سان متغير جو اعلان ڪرڻ جي اجازت ڏئي ٿو. هتي ساڳيا مثال آهن، پر لامبدا اظهار سان:
int counter = 0;
Runnable r = () -> counter++;
هي هڪ ئي سبب لاءِ مرتب نه ڪندو جيئن هڪ گمنام ڪلاس سان ورزن:  counterتبديل نه ٿيڻ گهرجي جڏهن پروگرام هلندي رهي. پر سڀ ڪجهه ٺيڪ آهي جيڪڏهن اسان ان کي هن طرح ڪندا آهيون:
final AtomicInteger counter = new AtomicInteger(0);
Runnable r = () -> counter.incrementAndGet();
اهو پڻ سڏڻ جي طريقن تي لاڳو ٿئي ٿو. lambda اظهار جي اندر، توهان نه رڳو رسائي ڪري سگهو ٿا سڀني "ڏسندڙ" متغيرن، پر ڪنهن به رسائي طريقن کي پڻ سڏين ٿا.
public class Main {

    public static void main(String[] args) {
        Runnable runnable = () -> staticMethod();
        new Thread(runnable).start();
    }

    private static void staticMethod() {

        System.out.println("I'm staticMethod(), and someone just called me!");
    }
}
جيتوڻيڪ staticMethod()خانگي آهي، اهو طريقي جي اندر رسائي آهي main()، تنهنڪري اهو پڻ سڏيو وڃي ٿو اندر اندر ٺاهيل ليمبڊا mainطريقي سان.

جڏهن هڪ ليمبڊا اظهار تي عمل ڪيو ويندو آهي؟

توھان کي ھيٺ ڏنل سوال تمام سادو ڳولي سگھي ٿو، پر توھان کي اھو ئي پڇڻ گھرجي: لامبڊا ايڪسپريس اندر ڪوڊ ڪڏھن تي عمل ڪيو ويندو؟ جڏهن اهو ٺهيل آهي؟ يا جڏهن سڏيو ويندو آهي (جيڪو اڃا تائين معلوم نه آهي)؟ اهو چيڪ ڪرڻ بلڪل آسان آهي.
System.out.println("Program start");

// All sorts of code here
// ...

System.out.println("Before lambda declaration");

Runnable runnable = () -> System.out.println("I'm a lambda!");

System.out.println("After lambda declaration");

// All sorts of other code here
// ...

System.out.println("Before passing the lambda to the thread");
new Thread(runnable).start();
اسڪرين آئوٽ:
Program start
Before lambda declaration
After lambda declaration
Before passing the lambda to the thread
I'm a lambda!
توهان ڏسي سگهو ٿا ته lambda ايڪسپريس تي عمل ڪيو ويو تمام آخر ۾، موضوع جي ٺهڻ کان پوء ۽ صرف جڏهن پروگرام جي عمل جي طريقي تي پهچي ٿي run(). يقينن نه جڏهن اهو اعلان ڪيو ويو آهي. هڪ لامبڊا اظهار جو اعلان ڪندي، اسان صرف هڪ Runnableاعتراض ٺاهيو آهي ۽ بيان ڪيو آهي ته ان جو run()طريقو ڪيئن آهي. اهو طريقو پاڻ کي گهڻو بعد ۾ لاڳو ڪيو ويندو آهي.

طريقن جو حوالو؟

طريقن جا حوالا سڌو سنئون لامبڊاس سان لاڳاپيل نه آهن، پر مان سمجهان ٿو ته هن مضمون ۾ انهن بابت ڪجهه لفظ چوڻ جو احساس آهي. فرض ڪريو اسان وٽ هڪ lambda اظهار آهي جيڪو ڪجهه خاص نٿو ڪري، پر صرف هڪ طريقو سڏيندو آهي.
x -> System.out.println(x)
اهو ڪجهه x۽ صرف ڪال وصول ڪري ٿو System.out.println()، گذري رهيو آهي x. انهي حالت ۾، اسان ان کي تبديل ڪري سگھون ٿا مطلوب طريقي جي حوالي سان. هن وانگر:
System.out::println
اھو صحيح آھي - آخر ۾ ڪو قوس نه آھي! هتي هڪ وڌيڪ مڪمل مثال آهي:
List<String> strings = new LinkedList<>();

strings.add("Dota");
strings.add("GTA5");
strings.add("Halo");

strings.forEach(x -> System.out.println(x));
آخري لڪير ۾، اسان forEach()طريقو استعمال ڪندا آهيون، جيڪو هڪ اعتراض وٺندو آهي جيڪو Consumerانٽرفيس کي لاڳو ڪري ٿو. ٻيهر، هي هڪ فنڪشنل انٽرفيس آهي، صرف هڪ void accept(T t)طريقو آهي. ان جي مطابق، اسان هڪ lambda ايڪسپريس لکندا آهيون جنهن ۾ هڪ پيٽرول هوندو آهي (ڇاڪاڻ ته اهو انٽرفيس ۾ ئي ٽائيپ ڪيو ويو آهي، اسان پيراميٽر جي قسم جي وضاحت نه ڪندا آهيون؛ اسان صرف اهو ظاهر ڪندا آهيون ته اسان ان کي سڏينداسين) x. لامبڊا ايڪسپريس جي جسم ۾، اسان اهو ڪوڊ لکون ٿا جيڪو عمل ڪيو ويندو جڏهن accept()طريقو سڏيو ويندو. هتي اسان صرف ڏيکاريون ٿا ته متغير ۾ ڇا ختم ٿيو x. اهو ساڳيو forEach()طريقو مجموعي ۾ سڀني عنصرن جي ذريعي ورجائي ٿو ۽ انٽرفيس (اسان جي ليمبڊا) accept()جي عمل تي طريقو سڏي ٿو Consumer، مجموعي ۾ هر شئي ۾ گذري ٿو. جيئن مون چيو ته، اسان اهڙي ليمبڊا ايڪسپريشن (جيڪو صرف هڪ مختلف طريقو ڪلاس ڪري ٿو) کي گهربل طريقي جي حوالي سان تبديل ڪري سگهون ٿا. پوء اسان جو ڪوڊ هن طرح نظر ايندو:
List<String> strings = new LinkedList<>();

strings.add("Dota");
strings.add("GTA5");
strings.add("Halo");

strings.forEach(System.out::println);
بنيادي شيء اها آهي ته پيرا ميٽرز println()۽ accept()طريقن سان ملن ٿا. ڇو جو println()طريقو ڪجھ به قبول ڪري سگھي ٿو (اھو سڀني پرائمري قسمن ۽ سڀني شين لاءِ اوورلوڊ ٿيل آھي)، ليمبڊا ايڪسپريسشن جي بدران، اسان صرف طريقي سان ھڪڙو حوالو ڏئي سگھون println()ٿا forEach(). ان کان پوء forEach()هر عنصر گڏ ڪرڻ ۾ وٺي ويندي ۽ ان کي سڌو println()طريقي سان منتقل ڪيو ويندو. هر ڪنهن لاءِ جيڪو پهريون ڀيرو هن سان منهن ڏئي رهيو آهي، مهرباني ڪري نوٽ ڪريو ته اسان ڪال نه ڪري رهيا آهيون System.out.println()(لفظن جي وچ ۾ نقطن سان ۽ آخر ۾ قوسین سان). ان جي بدران، اسان هن طريقي جي حوالي سان گذري رهيا آهيون. جيڪڏهن اسان هي لکنداسين
strings.forEach(System.out.println());
اسان وٽ گڏ ڪرڻ جي غلطي هوندي. ڪال ڪرڻ کان اڳ forEach()، جاوا ڏسي ٿو ته System.out.println()سڏيو پيو وڃي، تنهن ڪري اهو سمجهي ٿو ته واپسي جي قيمت آهي ۽ ان کي voidمنتقل ڪرڻ جي ڪوشش ڪندو ، جنهن جي بدران هڪ اعتراض جي توقع آهي. voidforEach()Consumer

طريقن جي حوالن لاء نحو

اهو بلڪل سادو آهي:
  1. اسان هن طرح هڪ جامد طريقي جو حوالو ڏيو ٿا:ClassName::staticMethodName

    public class Main {
    
        public static void main(String[] args) {
    
            List<String> strings = new LinkedList<>();
            strings.add("Dota");
            strings.add("GTA5");
            strings.add("Halo");
    
            strings.forEach(Main::staticMethod);
        }
    
        private static void staticMethod(String s) {
    
            // Do something
        }
    }
  2. اسان ھڪڙو حوالو ڏيو ھڪڙو غير جامد طريقي سان ھڪڙي موجوده اعتراض کي استعمال ڪندي، جھڙوڪ:objectName::instanceMethodName

    public class Main {
    
        public static void main(String[] args) {
    
            List<String> strings = new LinkedList<>();
            strings.add("Dota");
            strings.add("GTA5");
            strings.add("Halo");
    
            Main instance = new Main();
            strings.forEach(instance::nonStaticMethod);
        }
    
        private void nonStaticMethod(String s) {
    
            // Do something
        }
    }
  3. اسان ڪلاس استعمال ڪندي هڪ غير جامد طريقي جو حوالو ڏيون ٿا جيڪو ان کي هن ريت لاڳو ڪري ٿو:ClassName::methodName

    public class Main {
    
        public static void main(String[] args) {
    
            List<User> users = new LinkedList<>();
            users.add (new User("John"));
            users.add(new User("Paul"));
            users.add(new User("George"));
    
            users.forEach(User::print);
        }
    
        private static class User {
            private String name;
    
            private User(String name) {
                this.name = name;
            }
    
            private void print() {
                System.out.println(name);
            }
        }
    }
  4. اسان هن طرح هڪ تعمير ڪندڙ ڏانهن هڪ حوالو ڏيو ٿا:ClassName::new

    طريقن جا حوالا ڏاڍا آسان آهن جڏهن توهان وٽ اڳ ۾ ئي هڪ طريقو آهي جيڪو مڪمل طور تي ڪال بڪ طور ڪم ڪندو. انهي صورت ۾، هڪ ليمبڊا ايڪسپريس لکڻ جي بدران جنهن ۾ طريقي جي ڪوڊ شامل آهي، يا هڪ ليمبڊا ايڪسپريس لکڻ جيڪو صرف طريقو سڏيندو آهي، اسان صرف ان جو حوالو ڏيون ٿا. ۽ اهو آهي.

گمنام طبقن ۽ lambda اظهار جي وچ ۾ هڪ دلچسپ فرق

هڪ گمنام طبقي ۾، thisلفظ گمنام طبقي جي اعتراض ڏانهن اشارو ڪري ٿو. پر جيڪڏهن اسان هن کي استعمال ڪريون ٿا هڪ ليمبڊا اندر، اسان حاصل ڪريون ٿا پهچ واري اعتراض تائين. اهو جتي اسان اصل ۾ لکيو آهي لامبدا اظهار. اهو ان ڪري ٿئي ٿو ڇاڪاڻ ته ليمبڊا ايڪسپريشنز ڪلاس جي هڪ خانگي طريقي سان مرتب ڪيا ويا آهن جنهن ۾ اهي لکيل آهن. مان هن ”فيچر“ کي استعمال ڪرڻ جي سفارش نه ڪندس، ڇاڪاڻ ته ان جو هڪ طرفي اثر آهي ۽ اهو فنڪشنل پروگرامنگ جي اصولن جي تضاد آهي. اهو چيو ته، اهو طريقو مڪمل طور تي او او پي سان برابر آهي. ؛)

مون کي منهنجي معلومات ڪٿان ملي ۽ توهان کي ٻيو ڇا پڙهڻ گهرجي؟

۽، يقينا، مون کي گوگل تي هڪ ٽين سامان مليو :)
تبصرا
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION