سلام! Java Syntax Pro جستجو ۾، اسان لامبڊا ايڪسپريسز جو اڀياس ڪيو ۽ چيو ته اھي ھڪ فنڪشنل انٽرفيس مان ھڪ فنڪشنل طريقي تي عمل ڪرڻ کان وڌيڪ ڪجھ به نه آھن. ٻين لفظن ۾، اهو ڪجهه گمنام (نامعلوم) طبقي جو عمل آهي، ان جو غير حقيقي طريقو. ۽ جيڪڏهن ڪورس جي ليڪچرن ۾ اسان لامبڊا جي اظهارن سان ٺاهه ڪرڻ ۾ مشغول ٿي چڪا آهيون، هاڻي اسان غور ڪنداسين، تنهنڪري ڳالهائڻ لاء، ٻئي طرف: يعني، اهي تمام انٽرنيٽ. جاوا جي اٺين ورزن ۾ فنڪشنل انٽرفيس جو تصور متعارف ڪرايو . هي ڇا آهي؟ ھڪڙو انٽرفيس ھڪڙي غير لاڳو ٿيل (خلاصي) طريقي سان ڪم ڪري ٿو. ڪيتريون ئي ٻاهريون انٽرفيس هن تعريف هيٺ اچي وڃن ٿا، جهڙوڪ، مثال طور، اڳ ۾ بحث ڪيل انٽرفيس . ۽ پڻ انٽرفيس جيڪي اسان پاڻ ٺاهيندا آهيون، جهڙوڪ: اڳڪٿي ڪرڻ
ڪنڀار
فراهم ڪندڙ
فنڪشن
يونيري آپريٽر
Comparator
@FunctionalInterface
public interface Converter<T, N> {
N convert(T t);
}
اسان وٽ هڪ انٽرفيس آهي جنهن جو ڪم هڪ قسم جي شين کي ٻئي جي شين ۾ تبديل ڪرڻ آهي (هڪ قسم جو اڊاپٽر). تشريح @FunctionalInterface
ڪا وڏي پيچيده يا اهم نه آهي، ڇاڪاڻ ته ان جو مقصد اهو آهي ته مرتب ڪندڙ کي ٻڌايو ته هي انٽرفيس ڪم ڪندڙ آهي ۽ ان ۾ هڪ کان وڌيڪ طريقو نه هجڻ گهرجي. جيڪڏهن هن تشريح سان گڏ هڪ انٽرفيس هڪ کان وڌيڪ غير لاڳو ٿيل (خلاصو) طريقو آهي، مرتب ڪندڙ هن انٽرفيس کي نه ڇڏيندو، ڇاڪاڻ ته اهو ان کي غلط ڪوڊ سمجهي سگهندو. هن تشريح کان سواء انٽرفيس فنڪشنل سمجهي سگهجي ٿو ۽ ڪم ڪندو، پر @FunctionalInterface
اهو اضافي انشورنس کان وڌيڪ ڪجهه ناهي. اچو ته واپس ڪلاس ڏانهن وڃو Comparator
. جيڪڏھن توھان ان جو ڪوڊ ڏسو (يا دستاويز )، توھان ڏسي سگھوٿا ته ان ۾ ھڪڙي کان وڌيڪ طريقا آھن. پوء توهان پڇو: ڪيئن، پوء، ان کي هڪ فنڪشنل انٽرفيس سمجهي سگهجي ٿو؟ خلاصو انٽرفيس جا طريقا ٿي سگھن ٿا جيڪي ھڪڙي طريقي جي دائري ۾ نه آھن:
- جامد
@FunctionalInterface
public interface Converter<T, N> {
N convert(T t);
static <T> boolean isNotNull(T t){
return t != null;
}
}
اهو طريقو حاصل ڪرڻ کان پوء، مرتب ڪندڙ شڪايت نه ڪئي، جنهن جو مطلب آهي ته اسان جو انٽرفيس اڃا تائين ڪم ڪري رهيو آهي.
- ڊفالٽ طريقا
default
:
@FunctionalInterface
public interface Converter<T, N> {
N convert(T t);
static <T> boolean isNotNull(T t){
return t != null;
}
default void writeToConsole(T t) {
System.out.println("Текущий an object - " + t.toString());
}
}
ٻيهر، اسان ڏسون ٿا ته مرتب ڪندڙ شڪايت ڪرڻ شروع نه ڪيو، ۽ اسان فنڪشنل انٽرفيس جي حدن کان ٻاهر نه وڃو.
- اعتراض طبقي جا طريقا
Object
. اهو انٽرفيس تي لاڳو نٿو ٿئي. پر جيڪڏهن اسان وٽ انٽرفيس ۾ هڪ خلاصو طريقو آهي جيڪو دستخط سان ملندو آهي طبقي جي ڪنهن طريقي سان Object
، اهڙو طريقو (يا طريقا) اسان جي فنڪشنل انٽرفيس جي پابندي کي ٽوڙي نه سگهندو:
@FunctionalInterface
public interface Converter<T, N> {
N convert(T t);
static <T> boolean isNotNull(T t){
return t != null;
}
default void writeToConsole(T t) {
System.out.println("Текущий an object - " + t.toString());
}
boolean equals(Object obj);
}
۽ ٻيهر، اسان جو مرتب ڪندڙ شڪايت نه ڪندو آهي، تنهنڪري انٽرفيس Converter
اڃا تائين فنڪشنل سمجهيو ويندو آهي. هاڻي سوال اهو آهي ته: اسان کي هڪ فنڪشنل انٽرفيس ۾ هڪ غير لاڳو ٿيل طريقي سان پاڻ کي محدود ڪرڻ جي ضرورت آهي؟ ۽ پوء انهي ڪري ته اسان ان کي استعمال ڪري سگھون ٿا lambdas. اچو ته ان کي هڪ مثال سان ڏسو Converter
. هن کي ڪرڻ لاء، اچو ته هڪ ڪلاس ٺاهيو Dog
:
public class Dog {
String name;
int age;
int weight;
public Dog(final String name, final int age, final int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
}
۽ هڪ جهڙو Raccoon
(ريڪون):
public class Raccoon {
String name;
int age;
int weight;
public Raccoon(final String name, final int age, final int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
}
فرض ڪريو اسان وٽ هڪ اعتراض آهي Dog
، ۽ اسان کي ان جي فيلڊ جي بنياد تي هڪ اعتراض ٺاهڻ جي ضرورت آهي Raccoon
. اھو آھي، Converter
اھو ھڪڙي قسم جي ھڪڙي شيء کي ٻئي ۾ تبديل ڪري ٿو. اهو ڪيئن نظر ايندو:
public static void main(String[] args) {
Dog dog = new Dog("Bobbie", 5, 3);
Converter<Dog, Raccoon> converter = x -> new Raccoon(x.name, x.age, x.weight);
Raccoon raccoon = converter.convert(dog);
System.out.println("Raccoon has parameters: name - " + raccoon.name + ", age - " + raccoon.age + ", weight - " + raccoon.weight);
}
جڏهن اسان ان کي هلائيندا آهيون، اسان ڪنسول ڏانهن هيٺين آئوٽ حاصل ڪندا آهيون:
Raccoon has parameters: name - Bobbbie, age - 5, weight - 3
۽ هن جو مطلب آهي ته اسان جو طريقو صحيح ڪم ڪيو.
بنيادي جاوا 8 فنڪشنل انٽرفيس
خير، هاڻي اچو ته ڪيترن ئي فنڪشنل انٽرفيس تي نظر رکون جيڪي جاوا 8 اسان کي کڻي آيا آهن ۽ جيڪي فعال طور تي استعمال ڪيا ويا آهن اسٽريم API سان گڏ.اڳڪٿي ڪرڻ
Predicate
- هڪ فنڪشنل انٽرفيس چيڪ ڪرڻ لاءِ ته ڇا هڪ خاص شرط ملي ٿي. جيڪڏهن شرط پورا ٿي وڃي، واپسي true
، ٻي صورت ۾ - false
:
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
مثال طور، ھڪڙو ٺاھڻ تي غور ڪريو Predicate
جيڪو ھڪڙي قسم جي برابري جي جانچ ڪندو Integer
:
public static void main(String[] args) {
Predicate<Integer> isEvenNumber = x -> x % 2==0;
System.out.println(isEvenNumber.test(4));
System.out.println(isEvenNumber.test(3));
}
ڪنسول آئوٽ:
true
false
ڪنڀار
Consumer
(انگريزي کان - "صارف") - هڪ فنڪشنل انٽرفيس جيڪو T قسم جي اعتراض کي ان پٽ دليل طور وٺندو آهي، ڪجهه ڪارناما انجام ڏئي ٿو، پر ڪجھ به نه موٽائي ٿو:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
مثال جي طور تي، غور ڪريو ، جنهن جو ڪم اهو آهي ته ڪنسول ڏانهن هڪ سلام پيش ڪرڻ سان منظور ٿيل اسٽرنگ دليل سان: Consumer
public static void main(String[] args) {
Consumer<String> greetings = x -> System.out.println("Hello " + x + " !!!");
greetings.accept("Elena");
}
ڪنسول آئوٽ:
Hello Elena !!!
فراهم ڪندڙ
Supplier
(انگريزي - فراهم ڪندڙ کان) - هڪ فنڪشنل انٽرفيس جيڪو ڪو به دليل نٿو وٺي، پر T قسم جو اعتراض واپس ڪري ٿو:
@FunctionalInterface
public interface Supplier<T> {
T get();
}
مثال طور، غور ڪريو Supplier
، جيڪو ھڪڙي فهرست مان بي ترتيب نالا پيدا ڪندو:
public static void main(String[] args) {
ArrayList<String> nameList = new ArrayList<>();
nameList .add("Elena");
nameList .add("John");
nameList .add("Alex");
nameList .add("Jim");
nameList .add("Sara");
Supplier<String> randomName = () -> {
int value = (int)(Math.random() * nameList.size());
return nameList.get(value);
};
System.out.println(randomName.get());
}
۽ جيڪڏهن اسان هن کي هلائيندا آهيون، اسان ڏسنداسين بي ترتيب نتيجا ڪنسول ۾ نالن جي فهرست مان.
فنڪشن
Function
- هي فنڪشنل انٽرفيس هڪ دليل T وٺندو آهي ۽ ان کي قسم R جي اعتراض ڏانهن وڌائيندو آهي، جنهن جي نتيجي ۾ موٽايو ويندو آهي:
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
مثال طور، اچو ته وٺون ، جيڪو انگن کي اسٽرنگ فارميٽ ( ) مان نمبر فارميٽ ( ): Function
String
Integer
public static void main(String[] args) {
Function<String, Integer> valueConverter = x -> Integer.valueOf(x);
System.out.println(valueConverter.apply("678"));
}
جڏهن اسان ان کي هلائيندا آهيون، اسان ڪنسول ڏانهن هيٺين آئوٽ حاصل ڪندا آهيون:
678
PS: جيڪڏهن اسان نه رڳو انگ، پر ٻيا اکر پڻ اسٽرنگ ۾ داخل ڪريون ٿا، هڪ استثنا اڇلايو ويندو - NumberFormatException
.
يونيري آپريٽر
UnaryOperator
- ھڪڙو فنڪشنل انٽرفيس جيڪو ھڪڙي قسم جي ھڪڙي شيء کي پيراميٽر جي طور تي وٺي ٿو، ان تي ڪجھ آپريشن انجام ڏئي ٿو ۽ ساڳي قسم جي T جي ھڪڙي اعتراض جي صورت ۾ عملن جو نتيجو واپس ڪري ٿو:
@FunctionalInterface
public interface UnaryOperator<T> {
T apply(T t);
}
UnaryOperator
، جيڪو apply
هڪ نمبر چورس ڪرڻ لاءِ ان جو طريقو استعمال ڪري ٿو:
public static void main(String[] args) {
UnaryOperator<Integer> squareValue = x -> x * x;
System.out.println(squareValue.apply(9));
}
ڪنسول آئوٽ:
81
اسان پنج فنڪشنل انٽرفيس کي ڏٺو. اهو سڀ ڪجهه نه آهي جيڪو اسان وٽ موجود آهي جاوا 8 سان شروع ڪندي - اهي مکيه انٽرفيس آهن. باقي موجود آهن انهن جا پيچيده اينالاگ آهن. مڪمل فهرست سرڪاري Oracle دستاويزن ۾ ڳولهي سگھجي ٿو .
اسٽريم ۾ فنڪشنل انٽرفيس
جيئن مٿي بحث ڪيو ويو آهي، اهي فنڪشنل انٽرفيس مضبوط طور تي اسٽريم API سان گڏ آهن. ڪيئن، توهان پڇو؟ ۽ جيئن ته ڪيترائي طريقاStream
خاص طور تي انهن فنڪشنل انٽرفيس سان ڪم ڪن ٿا. اچو ته ڏسو ته ڪيئن فنڪشنل انٽرفيس استعمال ڪري سگھجن ٿيون Stream
.
Predicate سان طريقو
مثال طور، اچو ته طبقي جو طريقو وٺونStream
- filter
جيڪو هڪ دليل جي طور تي وٺندو آهي Predicate
۽ Stream
صرف اهي عنصر واپس آڻيندو آهي جيڪي شرط کي پورو ڪن ٿا Predicate
. جي حوالي سان Stream
-a، هن جو مطلب اهو آهي ته اهو صرف انهن عناصرن مان گذري ٿو جيڪي واپس ايندا آهن true
جڏهن توهان انهن کي test
انٽرفيس طريقي سان استعمال ڪندا آهيو Predicate
. اھو اھو آھي جيڪو اسان جو مثال جھڙو نظر ايندو Predicate
، پر عنصرن جي فلٽر لاءِ Stream
:
public static void main(String[] args) {
List<Integer> evenNumbers = Stream.of(1, 2, 3, 4, 5, 6, 7, 8)
.filter(x -> x % 2==0)
.collect(Collectors.toList());
}
نتيجي طور، فهرست evenNumbers
عناصر تي مشتمل هوندي {2, 4, 6, 8}. ۽، جيئن اسان کي ياد آهي، collect
اهو سڀني عناصر کي هڪ خاص مجموعي ۾ گڏ ڪندو: اسان جي صورت ۾، ۾ List
.
صارفين سان گڏ طريقو
طريقن مان هڪ آهيStream
، جيڪو فنڪشنل انٽرفيس استعمال ڪري ٿو Consumer
، اهو آهي peek
. اھو اھو آھي جيڪو اسان جي مثال Consumer
۾ نظر ايندو Stream
:
public static void main(String[] args) {
List<String> peopleGreetings = Stream.of("Elena", "John", "Alex", "Jim", "Sara")
.peek(x -> System.out.println("Hello " + x + " !!!"))
.collect(Collectors.toList());
}
ڪنسول آئوٽ:
Hello Elena !!!
Hello John !!!
Hello Alex !!!
Hello Jim !!!
Hello Sara !!!
پر جيئن ته طريقو peek
ڪم ڪري ٿو Consumer
، ان ۾ تارن جي ترميم Stream
نه ٿيندي، پر اصل عنصرن سان peek
واپس ايندي Stream
: ساڳيءَ طرح جيئن اهي آيون. تنهن ڪري، فهرست peopleGreetings
"ايلينا"، "جان"، "ايلڪس"، "جم"، "سارا" عناصر تي مشتمل هوندي. اتي پڻ ھڪڙو عام استعمال ٿيل طريقو آھي foreach
، جيڪو طريقو سان ملندڙ جلندڙ آھي peek
، پر فرق اھو آھي ته اھو حتمي آھي.
فراهم ڪندڙ سان طريقو
ھڪڙي طريقي جو ھڪڙو مثالStream
جيڪو استعمال ڪري ٿو فنڪشنل انٽرفيس Supplier
آھي generate
، جيڪو ان کي منظور ٿيل فنڪشنل انٽرفيس جي بنياد تي لامحدود تسلسل ٺاھي ٿو. اچو ته اسان جو مثال استعمال ڪريون Supplier
ڪنسول ۾ پنج بي ترتيب نالن کي پرنٽ ڪرڻ لاءِ:
public static void main(String[] args) {
ArrayList<String> nameList = new ArrayList<>();
nameList.add("Elena");
nameList.add("John");
nameList.add("Alex");
nameList.add("Jim");
nameList.add("Sara");
Stream.generate(() -> {
int value = (int) (Math.random() * nameList.size());
return nameList.get(value);
}).limit(5).forEach(System.out::println);
}
۽ اھو اھو آھي جيڪو اسان حاصل ڪندا آھيون ڪنسول ۾:
John
Elena
Elena
Elena
Jim
ھتي اسان استعمال ڪيو طريقو limit(5)
تي حد مقرر ڪرڻ لاءِ generate
، ٻي صورت ۾ پروگرام بي ترتيب نالن کي ڪنسول تي اڻڄاڻ طور پرنٽ ڪندو.
فنڪشن سان طريقو
Stream
دليل سان گڏ ھڪڙي طريقي جو ھڪڙو عام مثال Function
ھڪڙو طريقو آھي map
جيڪو ھڪڙي قسم جي عناصر کي وٺي ٿو، انھن سان ڪجھھ ڪري ٿو ۽ انھن کي منتقل ڪري ٿو، پر اھي اڳ ۾ ئي مختلف قسم جا عنصر ٿي سگھن ٿا. Function
ان ۾ ڪهڙو مثال نظر اچي سگهي ٿو Stream
:
public static void main(String[] args) {
List<Integer> values = Stream.of("32", "43", "74", "54", "3")
.map(x -> Integer.valueOf(x)).collect(Collectors.toList());
}
نتيجي طور، اسان کي انگن جي هڪ فهرست ملي ٿي، پر Integer
.
UnaryOperator سان طريقو
هڪ طريقي جي طور تي جيڪوUnaryOperator
هڪ دليل طور استعمال ڪري ٿو، اچو ته هڪ طبقي جو طريقو وٺو Stream
- iterate
. هي طريقو ان طريقي سان ملندڙ جلندڙ آهي generate
: اهو پڻ هڪ لامحدود تسلسل ٺاهي ٿو پر ٻه دليل آهن:
- پهريون اهو عنصر آهي جنهن مان تسلسل نسل شروع ٿئي ٿو.
- ٻيو آهي
UnaryOperator
، جيڪو پهريون عنصر مان نوان عنصر پيدا ڪرڻ جي اصول کي ظاهر ڪري ٿو.
UnaryOperator
، پر طريقي سان iterate
:
public static void main(String[] args) {
Stream.iterate(9, x -> x * x)
.limit(4)
.forEach(System.out::println);
}
جڏهن اسان ان کي هلائيندا آهيون، اسان ڪنسول ڏانهن هيٺين آئوٽ حاصل ڪندا آهيون:
9
81
6561
43046721
اهو آهي، اسان جو هر عنصر پاڻ ۾ ضرب ڪيو ويندو آهي، ۽ ائين ئي پهرين چئن انگن لاء. اهو ئي سڀ ڪجهه آهي! اهو تمام سٺو ٿيندو جيڪڏهن هن آرٽيڪل پڙهڻ کان پوءِ توهان جاوا ۾ اسٽريم API کي سمجهڻ ۽ ماهر ڪرڻ جي هڪ قدم ويجهو آهيو!
GO TO FULL VERSION