1. Giriş
Funksional interfeys — tərkibində məhz bir abstrakt metod olan (yəni reallaşdırması olmayan metod) interfeysdir. Məhz belə interfeys metodun reallaşdırılmasını yığcam yazmaq üçün istifadə olunur — Java-da bu, lambda ifadələri vasitəsilə edilir (onları sonra öyrənəcəyik).
Niyə yalnız bir metod?
Çünki funksional interfeys məhz bir əməliyyatı təsvir edir. Əgər metodlar iki və ya daha çox olsaydı, hansı metodun reallaşdırılmalı olduğu aydın olmazdı. Buna görə qayda sadədir: bir interfeys — bir abstrakt metod.
Standart kitabxanadan nümunələr
- Runnable — axınlarda tapşırıqlar üçün (void run())
- Callable<V> — nəticə qaytaran tapşırıqlar üçün (V call())
- Comparator<T> — obyektləri müqayisə etmək üçün (int compare(T o1, T o2))
- Consumer<T> — dəyərin “istehlakçısı” (void accept(T t))
- Supplier<T> — dəyərin “təchizatçısı” (T get())
- Function<T, R> — T-dən R-ə funksiya (R apply(T t))
- Predicate<T> — şərtin yoxlanması (boolean test(T t))
Məsələn, Runnable interfeysi:
public interface Runnable {
void run();
}
Və budur, Comparator interfeysi:
public interface Comparator<T> {
int compare(T o1, T o2);
// ... başqa default və static metodlar da var, amma abstrakt metod cəmi birdir!
}
Vacib məqam: default və static metodlar abstrakt sayılmır, buna görə də onlardan istədiyiniz qədər ola bilər!
2. Annotasiya @FunctionalInterface
Java — sərt və prinsipial bir xanımdır. Qarışıqlıq olmasın deyə, interfeysi açıq şəkildə funksional kimi @FunctionalInterface annotasiyası ilə işarələməyə imkan verir. Bu, “Yalnız bir düymə ilə işləyir!” stikerinə bənzəyir — kimsə artıq nəsə əlavə etməsin deyə.
@FunctionalInterface
public interface Operation {
int apply(int a, int b);
}
İndi, əgər birdən-birə unudub ikinci abstrakt metod əlavə etsəniz, kompilyator dərhal xəta barədə xəbər verəcək:
@FunctionalInterface
public interface Oops {
void doIt();
void doSomethingElse(); // Səhv! İki abstrakt metod
}
Annotasiya mütləqdirmi?
Xeyr, məcburi deyil. İnterfeys məhz bir abstrakt metoddan ibarətdirsə, o, onsuz da funksional olacaq. Lakin annotasiya ilə niyyətinizi açıq göstərir və özünüzü təsadüfi səhvlərdən qoruyursunuz.
default və static metodları əlavə etmək olarmı?
Bəli, olar! Əsas odur ki, yalnız bir abstrakt metod olsun. Qalan bütün metodlar istədiyiniz qədər default və ya static ola bilər.
Nümunə:
@FunctionalInterface
public interface FancyOperation {
int apply(int a, int b);
default void printInfo() {
System.out.println("Mən — fancy əməliyyatam!");
}
static void description() {
System.out.println("Arifmetika üçün funksional interfeys.");
}
}
3. Elan və istifadə nümunələri
Tutaq ki, iki ədəd üzərində əməliyyatı təsvir etmək istəyirsiniz. Bu, belə edilir:
@FunctionalInterface
public interface Operation {
int apply(int a, int b);
}
İndi bu interfeysi müxtəlif cür reallaşdırmaq olar.
Adi sinif vasitəsilə reallaşdırma
public class SumOperation implements Operation {
@Override
public int apply(int a, int b) {
return a + b;
}
}
İstifadə:
Operation sum = new SumOperation();
System.out.println(sum.apply(2, 3)); // 5
Anonim sinif vasitəsilə reallaşdırma
Operation multiply = new Operation() {
@Override
public int apply(int a, int b) {
return a * b;
}
};
System.out.println(multiply.apply(2, 3)); // 6
Lambdalar barədə qeyd
Java 8-dən başlayaraq bu cür interfeysləri lambda ifadələri — daha qısa sintaksis — ilə rahat reallaşdırmaq olur. Lambdaları bir neçə dərsdən sonra öyrənəcəyik, buna görə hələlik bilmək kifayətdir: funksional interfeyslər məhz onlarla maksimal rahat işləmək üçün yaradılıb.
4. Təcrübə: öz funksional interfeysini yaz
Tapşırıq 1. Öz Action-unuzu yaradın!
Sətir qəbul edən və heç nə qaytarmayan Action interfeysi yaradın. Onu sətiri böyük hərflərlə çap edən anonim sinif vasitəsilə reallaşdırın.
@FunctionalInterface
interface Action {
void act(String s);
}
public class ActionDemo {
public static void main(String[] args) {
Action shout = new Action() {
@Override
public void act(String text) {
System.out.println(text.toUpperCase());
}
};
shout.act("mən java öyrənirəm!"); // MƏN JAVA ÖYRƏNİRƏM!
}
}
(Sonradan bunu lambda ifadələri ilə daha qısa yazmağın mümkün olduğunu görəcəyik.)
Tapşırıq 2. Ədədlərin filtri
NumberPredicate interfeysini boolean test(int n) metodu ilə yaradın. Cüt olma yoxlamasını anonim sinif vasitəsilə reallaşdırın.
@FunctionalInterface
interface NumberPredicate {
boolean test(int n);
}
public class PredicateDemo {
public static void main(String[] args) {
NumberPredicate isEven = new NumberPredicate() {
@Override
public boolean test(int n) {
return n % 2 == 0;
}
};
System.out.println(isEven.test(4)); // true
System.out.println(isEven.test(7)); // false
}
}
Tapşırıq 3. Standart interfeyslərdən istifadə
Öz interfeysiniz əvəzinə hazır Predicate<Integer>-dən istifadə etmək olar:
import java.util.function.Predicate;
Predicate<Integer> isPositive = new Predicate<Integer>() {
@Override
public boolean test(Integer x) {
return x > 0;
}
};
System.out.println(isPositive.test(10)); // true
System.out.println(isPositive.test(-5)); // false
Cədvəl: standart kitabxanadakı funksional interfeyslər
| İnterfeys | Metod | Təsvir | Tətbiq nümunəsi |
|---|---|---|---|
|
|
Arqumentsiz və nəticəsiz tapşırıq | Axınlar, taymerlər |
|
|
Nəticəli tapşırıq | Axınlar, ExecutorService |
|
|
İki obyektin müqayisəsi | Kolleksiyaların sıralanması |
|
|
Dəyərin “istehlakçısı” | Kolleksiya üzərində iterasiya |
|
|
Dəyərin “təchizatçısı” | Tənbəl inisializasiya, məlumatların yaradılması |
|
|
T-dən R-ə funksiya | Məlumatların çevrilməsi |
|
|
Şərtin yoxlanması | Kolleksiyaların filtrasiyası |
5. Funksional interfeyslərlə işləyərkən tipik səhvlər
Səhv №1: ikinci abstrakt metod əlavə olunub. Əgər interfeys bir neçə abstrakt metoddan ibarətdirsə, o, artıq funksional deyil. Kompilyator (xüsusən də @FunctionalInterface ilə) dərhal xəta barədə xəbər verəcək.
Səhv №2: default və static metodların abstrakt sayılmadığını unutmusunuz. Onları funksional interfeysə rahatlıqla əlavə edə bilərsiniz — bu, “bir abstrakt metod” qaydasını pozmur.
Səhv №3: metodun siqnatürasını səhv reallaşdırmısınız. Məsələn, interfeys iki arqument tələb edir, siz isə metodu yalnız bir arqumentlə yazmısınız. Həmişə siqnaturaları yoxlayın.
Səhv №4: @FunctionalInterface-dən istifadə etmirsiniz və interfeysi təsadüfən korlayırsınız. İnterfeysi annotasiya ilə işarələməsəniz, təsadüfən artıq metod əlavə edə bilərsiniz — sonra isə niyə kodun işləmədiyini uzun müddət axtararsınız. Daha yaxşısı, həmişə niyyəti açıq göstərmək üçün annotasiyanı əlavə edin.
GO TO FULL VERSION