هي مضمون ڪنهن لاءِ آهي؟
- انهن لاءِ جيڪي هن مضمون جو پهريون حصو پڙهندا آهن؛
- انهن لاءِ جيڪي سمجهن ٿا ته اهي اڳ ۾ ئي جاوا ڪور کي چڱي طرح ڄاڻن ٿا، پر جاوا ۾ لامبڊا اظهار بابت ڪا ڄاڻ ناهي. يا، شايد، توهان اڳ ۾ ئي ڪجهه ٻڌو آهي ليمبڊاس بابت، پر تفصيل کان سواء.
- انهن لاءِ جن کي لامبڊا جي اظهار جي ڪجهه سمجهه آهي، پر اڃا تائين انهن کي استعمال ڪرڻ کان ڊپ ۽ غير معمولي آهن.
خارجي متغيرات تائين رسائي
ڇا هي ڪوڊ هڪ گمنام طبقي سان گڏ ڪندو؟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()
. متغير جي قيمت پاڻ تبديل نه ٿيندي آهي جڏهن ته پروگرام هلندي آهي ۽ هميشه هڪ ئي اعتراض ڏانهن اشارو ڪري ٿو، جيڪو اسان کي هڪ متغير کي فوري طور تي لفظ سان اعلان ڪرڻ جي اجازت ڏئي ٿو final
. ساڳيا مثال، پر لامبدا اظهار سان:
int counter = 0;
Runnable r = () -> counter++;
اهو هڪ ئي سبب سان گڏ نه آهي جيئن هڪ گمنام طبقي سان اختيار: counter
ان کي تبديل نه ٿيڻ گهرجي جڏهن پروگرام هلندي آهي. پر هن وانگر - سڀ ڪجهه ٺيڪ آهي:
final AtomicInteger counter = new AtomicInteger(0);
Runnable r = () -> counter.incrementAndGet();
اهو پڻ سڏڻ جي طريقن تي لاڳو ٿئي ٿو. ليمبڊا جي اظهار جي اندر کان، توهان نه صرف رسائي حاصل ڪري سگهو ٿا سڀ ”ڏسندڙ“ متغيرات، پر انهن طريقن کي پڻ سڏين ٿا جيڪي توهان وٽ آهن.
public class Main {
public static void main(String[] args) {
Runnable runnable = () -> staticMethod();
new Thread(runnable).start();
}
private static void staticMethod() {
System.out.println("Я - метод staticMethod(), и меня только-что кто-то вызвал!");
}
}
جيتوڻيڪ اهو طريقو staticMethod()
خانگي آهي، اهو "رسائي لائق" آهي جنهن کي طريقي جي اندر سڏيو وڃي ٿو main()
، تنهنڪري اهو پڻ دستياب آهي اندر کان ڪال ڪرڻ لاء ليمبڊا جيڪو طريقو ۾ ٺاهيو ويو آهي main
.
lambda ايڪسپريس ڪوڊ جي عملدرآمد جو لمحو
اهو سوال توهان کي تمام سادو لڳي سگهي ٿو، پر اهو سڀ ڪجهه پڇڻ جي لائق آهي: لامبڊا ايڪسپريس جي اندر ڪوڊ کي ڪڏهن جاري ڪيو ويندو؟ تخليق جي وقت تي؟ يا ان وقت جڏهن (اڃا تائين نامعلوم آهي) اهو ڪٿي سڏيو ويندو؟ اهو چيڪ ڪرڻ بلڪل آسان آهي.System.out.println("Запуск программы");
// много всякого разного codeа
// ...
System.out.println("Перед объявлением лямбды");
Runnable runnable = () -> System.out.println("Я - лямбда!");
System.out.println("После объявления лямбды");
// много всякого другого codeа
// ...
System.out.println("Перед передачей лямбды в тред");
new Thread(runnable).start();
ڊسپلي تي آئوٽ:
Запуск программы
Перед объявлением лямбды
После объявления лямбды
Перед передачей лямбды в тред
Я - лямбда!
اهو ڏسي سگھجي ٿو ته لامبڊا ايڪسپريس ڪوڊ تمام آخر ۾ عمل ڪيو ويو، موضوع جي ٺهڻ کان پوء ۽ صرف جڏهن پروگرام جي عمل جي عمل کي طريقي جي حقيقي عمل تي پهچي ويو run()
. ۽ نه ئي ان جي اعلان جي وقت تي. هڪ لامبڊا اظهار جو اعلان ڪندي، اسان صرف قسم جو هڪ اعتراض ٺاهيو Runnable
۽ ان جي طريقي جي رويي کي بيان ڪيو run()
. طريقو پاڻ کي گهڻو پوء شروع ڪيو ويو.
طريقو حوالو؟
سڌو سنئون لامبڊاس سان لاڳاپيل ناهي، پر منهنجو خيال آهي ته هن مضمون ۾ ان بابت ڪجهه لفظ چوڻ منطقي هوندو. اچو ته اسان وٽ هڪ لامبڊا اظهار آهي جيڪو ڪجهه خاص نٿو ڪري، پر صرف ڪجهه طريقو سڏيندو آهي.x -> System.out.println(x)
هنن هن کي ڪجهه ڏنو х
، ۽ اهو صرف هن کي سڏيو System.out.println()
۽ هن کي اتي پهچايو х
. انهي حالت ۾، اسان ان کي تبديل ڪري سگھون ٿا هڪ لنڪ سان جيڪو اسان کي گهربل آهي. هن وانگر:
System.out::println
ها، بغير قوس جي آخر ۾! وڌيڪ مڪمل مثال:
List<String> strings = new LinkedList<>();
strings.add("Mother");
strings.add("soap");
strings.add("frame");
strings.forEach(x -> System.out.println(x));
آخري لڪير تي اسان هڪ طريقو استعمال ڪندا آهيون forEach()
جيڪو قبول ڪري ٿو هڪ انٽرفيس اعتراض Consumer
. هي وري هڪ فنڪشنل انٽرفيس آهي صرف هڪ طريقي سان void accept(T t)
. ان مطابق، اسان هڪ ليمبڊا ايڪسپريشن لکون ٿا جيڪو هڪ پيرا ميٽر وٺي ٿو (جيئن ته اهو انٽرفيس ۾ ئي ٽائيپ ڪيو ويو آهي، اسان پيراميٽر جي قسم کي ظاهر نه ڪندا آهيون، پر اهو اشارو ڪيو ويندو ته ان کي سڏيو ويندو х)
. lambda ايڪسپريس جي جسم ۾ اسان ڪوڊ لکندا آهيون. جنهن تي عمل ڪيو ويندو جڏهن ميٿڊ کي سڏيو ويندو accept()
. هتي اسان صرف اسڪرين تي ڏيکاريون ٿا ته متغير ۾ ڇا آهي х
. طريقو پاڻ کي forEach()
گڏ ڪرڻ جي سڀني عنصرن مان گذري ٿو، Consumer
ان کي پاس ڪيل انٽرفيس اعتراض جي طريقي کي سڏي ٿو (اسان جي lambda) accept()
، جتي اهو هر عنصر کي ڪليڪشن مان پاس ڪري ٿو. جيئن مون اڳ ۾ چيو آهي، هي هڪ lambda-expression آهي (صرف هڪ ٻئي طريقي کي سڏيندي) اسان کي گهربل طريقي جي حوالي سان تبديل ڪري سگهون ٿا. پوء اسان جو ڪوڊ هن طرح نظر ايندو:
List<String> strings = new LinkedList<>();
strings.add("Mother");
strings.add("soap");
strings.add("frame");
strings.forEach(System.out::println);
بنيادي شيء اها آهي ته طريقن جي قبول ٿيل پيراگراف (println()
۽ accept())
. جيئن ته طريقو println()
ڪنهن به شيءِ کي قبول ڪري سگهي ٿو (اهو سڀني ابتدائي ۽ ڪنهن به شئي لاءِ اوور لوڊ ٿيل آهي)، ليمبڊا ايڪسپريشن جي بدران، اسان forEach()
صرف طريقي جي حوالي سان پاس ڪري سگهون ٿا println()
. پوء forEach()
اهو مجموعي جي هر عنصر کي وٺي ۽ سڌو ان کي منتقل ڪندو. println()
انهن لاءِ جيڪي پهريون ڀيرو هن سان منهن ڏئي رهيا آهن، مهرباني ڪري نوٽ ڪريو ته اسان ان طريقي کي نه ٿا سڏيون (لفظن جي وچ ۾ System.out.println()
نقطا ۽ آخر ۾ بریکٹ سان)، بلڪه اسان هن طريقي جو حوالو پاڻ ڏانهن منتقل ڪريون ٿا.
strings.forEach(System.out.println());
اسان وٽ گڏ ڪرڻ جي غلطي هوندي. ڇاڪاڻ ته ڪال کان اڳ forEach()
، جاوا ڏسندو ته ان کي سڏيو پيو وڃي System.out.println()
، اهو سمجھندو ته اهو واپس ڪيو پيو وڃي ۽ ان کي ان قسم جي اعتراض ڏانهن منتقل ڪرڻ جي void
ڪوشش ڪندو جيڪو اتي انتظار ڪري رهيو آهي . void
forEach()
Consumer
طريقن جي حوالي سان استعمال ڪرڻ لاء نحو
اهو تمام سادو آهي:-
هڪ جامد طريقي جي حوالي سان پاس ڪرڻ
NameКласса:: NameСтатическогоМетода?
public class Main { public static void main(String[] args) { List<String> strings = new LinkedList<>(); strings.add("Mother"); strings.add("soap"); strings.add("frame"); strings.forEach(Main::staticMethod); } private static void staticMethod(String s) { // do something } }
-
موجوده اعتراض کي استعمال ڪندي غير جامد طريقي جي حوالي سان پاس ڪرڻ
NameПеременнойСОбъектом:: method name
public class Main { public static void main(String[] args) { List<String> strings = new LinkedList<>(); strings.add("Mother"); strings.add("soap"); strings.add("frame"); Main instance = new Main(); strings.forEach(instance::nonStaticMethod); } private void nonStaticMethod(String s) { // do something } }
-
اسان ڪلاس استعمال ڪندي هڪ غير جامد طريقي جو حوالو ڏيو ٿا جنهن ۾ اهڙي طريقي تي عمل ڪيو ويو آهي
NameКласса:: method name
public class Main { public static void main(String[] args) { List<User> users = new LinkedList<>(); users.add(new User("Vasya")); users.add(new User("Коля")); users.add(new User("Петя")); 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); } } }
-
ڪنسٽرڪٽر ڏانهن لنڪ پاس
NameКласса::new
ڪرڻ جو طريقو لنڪس استعمال ڪرڻ تمام آسان آهي جڏهن هڪ تيار ٿيل طريقو آهي جنهن سان توهان مڪمل طور تي مطمئن آهيو، ۽ توهان ان کي ڪال بڪ طور استعمال ڪرڻ چاهيندا. انهي صورت ۾، انهي طريقي جي ڪوڊ سان ليمبڊا ايڪسپريس لکڻ جي بدران، يا هڪ ليمبڊا ايڪسپريس جتي اسان صرف هن طريقي کي سڏين ٿا، اسان صرف ان جو حوالو ڏيو. اهو ئي سڀ ڪجهه آهي.
گمنام طبقي ۽ لامبڊا اظهار جي وچ ۾ دلچسپ فرق
هڪ گمنام طبقي ۾، لفظthis
ان گمنام طبقي جي اعتراض ڏانهن اشارو ڪري ٿو. ۽ جيڪڏهن اسان ان کي استعمال ڪريون ٿا this
ليمبڊا اندر، اسان حاصل ڪنداسين فريمنگ ڪلاس جي اعتراض تائين. جتي اسان اصل ۾ هي اظهار لکيو آهي. اهو ٿي سگهي ٿو ڇاڪاڻ ته لامبڊا اظهار، جڏهن مرتب ڪيو وڃي ٿو، طبقي جو هڪ خانگي طريقو بڻجي وڃي ٿو جتي اهي لکيل آهن. مان هن ”فيچر“ کي استعمال ڪرڻ جي سفارش نه ڪندس، ڇاڪاڻ ته ان جو هڪ طرفي اثر آهي، جيڪو فنڪشنل پروگرامنگ جي اصولن جي تضاد آهي. پر اهو طريقو OOP سان ڪافي مطابقت رکي ٿو. ؛)
مون کي معلومات ڪٿان ملي يا ٻيو ڇا پڙهان
- سرڪاري Oracle ويب سائيٽ تي سبق . تمام گهڻو، تفصيل سان، مثالن سان، پر انگريزيءَ ۾.
- ساڳيو "Oracle" سبق ، پر باب طريقو حوالن بابت آهي.
- فنڪشنل پروگرامنگ بابت Habré تي هڪ مضمون (ٻي مضمون جو ترجمو). ليمبڊاس بابت تمام ٿورا گهڻا ڪتاب آهن، ڇاڪاڻ ته اهي عام طور تي فنڪشنل پروگرامنگ بابت آهن.
- انهن لاءِ جيڪي وڪيپيڊيا تي بيهڻ پسند ڪندا آهن .
- ۽، يقينا، مون کي گوگل تي شين جو هڪ گروپ مليو :)
GO TO FULL VERSION