Salom! Java Syntax Pro kvestida biz lambda ifodalarini o'rganib chiqdik va ular funktsional interfeysdan funktsional usulni amalga oshirishdan boshqa narsa emasligini aytdik. Boshqacha qilib aytganda, bu qandaydir anonim (noma'lum) sinfning amalga oshirilishi, uning amalga oshirilmagan usuli. Va agar kurs ma'ruzalarida biz lambda iboralari bilan manipulyatsiyani o'rgangan bo'lsak, endi biz boshqacha aytganda, boshqa tomonni ko'rib chiqamiz: aynan mana shu interfeyslar. Java ning sakkizinchi versiyasi funktsional interfeyslar tushunchasini taqdim etdi . Bu nima? Bitta amalga oshirilmagan (mavhum) usulga ega interfeys funktsional hisoblanadi. Ko'pgina tashqi interfeyslar ushbu ta'rifga kiradi, masalan, avval muhokama qilingan interfeys . Shuningdek, biz o'zimiz yaratadigan interfeyslar, masalan: Predikat
Iste'molchi
Yetkazib beruvchi
Funktsiya
UnaryOperator
Comparator
@FunctionalInterface
public interface Converter<T, N> {
N convert(T t);
}
Bizda interfeys mavjud, uning vazifasi bir turdagi ob'ektlarni boshqa turdagi ob'ektlarga aylantirishdir (adapter turi). Izoh @FunctionalInterface
juda murakkab yoki muhim narsa emas, chunki uning maqsadi kompilyatorga ushbu interfeys funktsional ekanligini va bir nechta usuldan iborat bo'lmasligi kerakligini aytishdir. Agar ushbu izohli interfeys bir nechta bajarilmagan (mavhum) usullarga ega bo'lsa, kompilyator bu interfeysni o'tkazib yubormaydi, chunki u uni xato kod sifatida qabul qiladi. Ushbu izohsiz interfeyslarni funktsional deb hisoblash mumkin va ishlaydi, ammo @FunctionalInterface
bu qo'shimcha sug'urtadan boshqa narsa emas. Keling, sinfga qaytaylik Comparator
. Agar siz uning kodiga (yoki hujjatlariga ) qarasangiz , unda bir nechta usullar mavjudligini ko'rishingiz mumkin. Keyin siz so'raysiz: qanday qilib uni funktsional interfeys deb hisoblash mumkin? Mavhum interfeyslar bitta usul doirasida bo'lmagan usullarga ega bo'lishi mumkin:
- statik
@FunctionalInterface
public interface Converter<T, N> {
N convert(T t);
static <T> boolean isNotNull(T t){
return t != null;
}
}
Ushbu usulni olgandan so'ng, kompilyator shikoyat qilmadi, ya'ni bizning interfeysimiz hali ham ishlaydi.
- standart usullar
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());
}
}
Yana shuni ko'ramizki, kompilyator shikoyat qilishni boshlamagan va biz funktsional interfeys cheklovlaridan tashqariga chiqmadik.
- Obyekt klassi usullari
Object
. Bu interfeyslarga taalluqli emas. Ammo interfeysda sinfning ba'zi bir usuli bilan imzoga mos keladigan mavhum usul mavjud bo'lsa Object
, bunday usul (yoki usullar) bizning funktsional interfeys cheklovimizni buzmaydi:
@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);
}
Va yana, bizning kompilyatorimiz shikoyat qilmaydi, shuning uchun interfeys Converter
hali ham funktsional hisoblanadi. Endi savol tug'iladi: nima uchun biz funktsional interfeysda o'zimizni bitta amalga oshirilmagan usul bilan cheklashimiz kerak? Va keyin biz uni lambdalar yordamida amalga oshirishimiz uchun. Keling, buni misol bilan ko'rib chiqaylik Converter
. Buning uchun sinf yaratamiz 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;
}
}
Va shunga o'xshash Raccoon
(rakun):
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;
}
}
Faraz qilaylik, bizda ob'ekt bor Dog
va biz uning maydonlari asosida ob'ekt yaratishimiz kerak Raccoon
. Ya'ni, Converter
u bir turdagi ob'ektni boshqasiga aylantiradi. Bu qanday ko'rinishga ega bo'ladi:
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);
}
Uni ishga tushirganimizda konsolga quyidagi natijani olamiz:
Raccoon has parameters: name - Bobbbie, age - 5, weight - 3
Va bu bizning usulimiz to'g'ri ishlaganligini anglatadi.
Asosiy Java 8 Funktsional interfeyslari
Xo'sh, endi Java 8 bizga olib kelgan va Stream API bilan birgalikda faol ishlatiladigan bir nechta funktsional interfeyslarni ko'rib chiqaylik.Predikat
Predicate
— muayyan shart bajarilganligini tekshirish uchun funksional interfeys. Agar shart bajarilsa, qaytariladi true
, aks holda - false
:
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
}
Misol sifatida, Predicate
bir qator turdagi paritetni tekshiradigan ni yaratishni ko'rib chiqing 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));
}
Konsol chiqishi:
true
false
Iste'molchi
Consumer
(ingliz tilidan - "iste'molchi") - T tipidagi ob'ektni kirish argumenti sifatida qabul qiladigan, ba'zi harakatlarni bajaradigan, lekin hech narsa qaytarmaydigan funktsional interfeys:
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
}
Misol sifatida, topshirilgan qator argumenti bilan konsolga salomlashish vazifasini ko'rib chiqing: Consumer
public static void main(String[] args) {
Consumer<String> greetings = x -> System.out.println("Hello " + x + " !!!");
greetings.accept("Elena");
}
Konsol chiqishi:
Hello Elena !!!
Yetkazib beruvchi
Supplier
(ingliz tilidan - provayder) - hech qanday argumentlarni qabul qilmaydigan, lekin T tipidagi ob'ektni qaytaradigan funktsional interfeys:
@FunctionalInterface
public interface Supplier<T> {
T get();
}
Misol sifatida, Supplier
ro'yxatdagi tasodifiy nomlarni keltirib chiqaradigan ni ko'rib chiqing:
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());
}
Va agar biz buni ishga tushirsak, konsoldagi nomlar ro'yxatidan tasodifiy natijalarni ko'ramiz.
Funktsiya
Function
— bu funksional interfeys T argumentini oladi va uni R tipidagi obyektga yuboradi, natijada u qaytariladi:
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
Misol sifatida raqamlarni satr formatidan ( ) raqam formatiga ( ) o'zgartiradigan ni olaylik : Function
String
Integer
public static void main(String[] args) {
Function<String, Integer> valueConverter = x -> Integer.valueOf(x);
System.out.println(valueConverter.apply("678"));
}
Uni ishga tushirganimizda konsolga quyidagi natijani olamiz:
678
PS: agar biz faqat raqamlarni emas, balki boshqa belgilarni ham satrga o'tkazsak, istisno tashlanadi - NumberFormatException
.
UnaryOperator
UnaryOperator
— T tipidagi ob'ektni parametr sifatida qabul qiluvchi, u ustida ba'zi amallarni bajaradigan va amallar natijasini bir xil T turdagi ob'ekt ko'rinishida qaytaradigan funktsional interfeys:
@FunctionalInterface
public interface UnaryOperator<T> {
T apply(T t);
}
UnaryOperator
, bu apply
raqamni kvadrat qilish uchun o'z usulidan foydalanadi:
public static void main(String[] args) {
UnaryOperator<Integer> squareValue = x -> x * x;
System.out.println(squareValue.apply(9));
}
Konsol chiqishi:
81
Biz beshta funktsional interfeysni ko'rib chiqdik. Bu Java 8 dan boshlab biz uchun mavjud bo'lgan hamma narsa emas - bu asosiy interfeyslar. Qolgan mavjud bo'lganlar ularning murakkab analoglari. To'liq ro'yxatni rasmiy Oracle hujjatlarida topish mumkin .
Streamdagi funktsional interfeyslar
Yuqorida muhokama qilinganidek, bu funktsional interfeyslar Stream API bilan chambarchas bog'langan. Qanday qilib, deb so'rayapsizmi? Va shuning uchun ko'plab usullarStream
ushbu funktsional interfeyslar bilan ishlaydi. Funktsional interfeyslardan qanday foydalanish mumkinligini ko'rib chiqamiz Stream
.
Predikat bilan usul
Misol uchun, sinf usulini olaylikStream
- filter
bu argument sifatida qabul qilinadi Predicate
va Stream
faqat shartni qondiradigan elementlarni qaytaradi Predicate
. -a kontekstida bu faqat interfeys usulida foydalanilganda Stream
qaytariladigan elementlardan o'tishini anglatadi . Bizning misolimiz shunday ko'rinadi , lekin quyidagi elementlar filtri uchun : 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());
}
Natijada, ro'yxat evenNumbers
{2, 4, 6, 8} elementlardan iborat bo'ladi. Va biz eslaganimizdek, collect
u barcha elementlarni ma'lum bir to'plamga to'playdi: bizning holatlarimizda List
.
Iste'molchi bilan ishlash usuli
Stream
Funktsional interfeysdan foydalanadigan usullardan biri Consumer
bu peek
. Consumer
Bizning misolimiz shunday ko'rinadi 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());
}
Konsol chiqishi:
Hello Elena !!!
Hello John !!!
Hello Alex !!!
Hello Jim !!!
Hello Sara !!!
Ammo usul peek
bilan ishlaganligi sababli Consumer
, satrlarni o'zgartirish Stream
sodir bo'lmaydi, lekin asl elementlar bilan peek
qaytadi Stream
: ular qanday kelgan bo'lsa, xuddi shunday. Shuning uchun ro'yxat peopleGreetings
"Elena", "Jon", "Aleks", "Jim", "Sara" elementlaridan iborat bo'ladi. foreach
Usulga o'xshash tez-tez ishlatiladigan usul ham mavjud peek
, ammo farqi shundaki, u yakuniy - terminal.
Yetkazib beruvchi bilan usul
Stream
Funktsional interfeysdan foydalanadigan usulga misol Supplier
bo'lib generate
, unga o'tkazilgan funktsional interfeys asosida cheksiz ketma-ketlikni hosil qiladi. Supplier
Keling , konsolga beshta tasodifiy nomni chop etish uchun misolimizdan foydalanamiz :
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);
}
Va bu konsolda olingan natija:
John
Elena
Elena
Elena
Jim
limit(5)
Bu erda biz usulga cheklov o'rnatish uchun usuldan foydalandik generate
, aks holda dastur tasodifiy nomlarni konsolga cheksiz ravishda chop etadi.
Funktsiya bilan usul
Stream
Argumentli usulning odatiy namunasi - bu bir turdagi elementlarni oladigan, ular bilan biror narsa qiladigan va ularni uzatadigan Function
usul , ammo bular allaqachon boshqa turdagi elementlar bo'lishi mumkin. in map
bilan misol qanday ko'rinishi mumkin : 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());
}
Natijada biz raqamlar ro'yxatini olamiz, lekin ichida Integer
.
UnaryOperator bilan usul
Argument sifatida foydalanadigan usul sifatidaUnaryOperator
sinf usulini olaylik Stream
- iterate
. Bu usul usulga o'xshaydi generate
: u cheksiz ketma-ketlikni ham yaratadi, lekin ikkita argumentga ega:
- birinchisi - ketma-ketlikni yaratish boshlanadigan element;
- ikkinchisi
UnaryOperator
- birinchi elementdan yangi elementlarni yaratish tamoyilini ko'rsatadi.
UnaryOperator
, lekin usulda iterate
:
public static void main(String[] args) {
Stream.iterate(9, x -> x * x)
.limit(4)
.forEach(System.out::println);
}
Uni ishga tushirganimizda konsolga quyidagi natijani olamiz:
9
81
6561
43046721
Ya'ni, har bir elementimiz o'z-o'zidan ko'paytiriladi va birinchi to'rtta raqam uchun. Ana xolos! Agar ushbu maqolani o'qib chiqqaningizdan so'ng Java-dagi Stream API-ni tushunish va o'zlashtirishga bir qadam yaqinlashsangiz juda yaxshi bo'lardi!
GO TO FULL VERSION