JavaRush /Java Blogu /Random-AZ /Lambda ifadələri nümunələrlə

Lambda ifadələri nümunələrlə

Qrupda dərc edilmişdir
Java əvvəlcə tamamilə obyekt yönümlü bir dildir. Primitiv tiplər istisna olmaqla, Java-da hər şey bir obyektdir. Hətta massivlər də obyektdir. Hər bir sinfin nümunələri obyektlərdir. Funksiyanı ayrıca təyin etmək üçün vahid imkan yoxdur (sinifdən kənarda - təqribən tərcümə. ). Bir metodu arqument kimi ötürmək və ya başqa bir metodun nəticəsi olaraq metod gövdəsini qaytarmaq üçün heç bir yol yoxdur. Elə bil. Amma bu, Java 8-dən əvvəl idi Nümunələrlə lambda ifadələri - 1. Yaxşı köhnə Swing günlərindən bəzi funksiyaları hansısa metoda ötürmək lazım gəldikdə anonim siniflər yazmaq lazım idi. Məsələn, hadisə idarəedicisini əlavə etmək belə görünür:
someObject.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {

                //Event listener implementation goes here...

            }
        });
Burada biz siçan hadisəsi dinləyicisinə bəzi kodlar əlavə etmək istəyirik. Biz anonim sinif müəyyən etdik MouseAdaptervə dərhal ondan obyekt yaratdıq. Bu yolla biz əlavə funksionallığı addMouseListener. Bir sözlə, Java-da sadə metodu (funksionallığı) arqumentlər vasitəsilə ötürmək asan deyil. Bu məhdudiyyət Java 8 tərtibatçılarını dil spesifikasiyasına Lambda ifadələri kimi bir xüsusiyyət əlavə etməyə məcbur etdi.

Java niyə Lambda ifadələrinə ehtiyac duyur?

Əvvəldən Java dili Annotasiyalar, Generics və s. kimi şeylər istisna olmaqla çox təkamül etməyib. Əvvəla, Java həmişə obyekt yönümlü olaraq qalıb. JavaScript kimi funksional dillərlə işlədikdən sonra Java-nın necə ciddi şəkildə obyekt yönümlü və güclü şəkildə yazıldığını başa düşmək olar. Java-da funksiyalara ehtiyac yoxdur. Öz-özünə Java dünyasında onları tapmaq mümkün deyil. Funksional proqramlaşdırma dillərində funksiyalar ön plana çıxır. Onlar öz-özlüyündə mövcuddurlar. Siz onları dəyişənlərə təyin edə və arqumentlər vasitəsilə digər funksiyalara ötürə bilərsiniz. JavaScript funksional proqramlaşdırma dillərinin ən yaxşı nümunələrindən biridir. İnternetdə JavaScript-in funksional dil kimi üstünlüklərini ətraflı izah edən yaxşı məqalələr tapa bilərsiniz. Funksional dillərdə tətbiqlərin yazılmasının ənənəvi üsulları ilə müqayisədə bir sıra üstünlüklər təmin edən Closure kimi güclü alətlər var. Bağlama ona əlavə edilmiş mühit olan funksiyadır - funksiyanın bütün yerli olmayan dəyişənlərinə istinadları saxlayan cədvəl. Java-da bağlamalar Lambda ifadələri vasitəsilə simulyasiya edilə bilər. Əlbəttə ki, bağlamalar və Lambda ifadələri arasında kiçik deyil, fərqlər var, lakin lambda ifadələri bağlanmalara yaxşı alternativdir. Stiv Yegge özünün sarkastik və gülməli bloqunda Java dünyasının ciddi şəkildə isimlərlə necə əlaqəli olduğunu təsvir edir (varlıqlar, obyektlər - təqribən tərcümə ). Əgər onun bloqunu oxumamısınızsa, onu tövsiyə edirəm. O, Lambda ifadələrinin Java-ya əlavə edilməsinin dəqiq səbəbini gülməli və maraqlı şəkildə təsvir edir. Lambda ifadələri Java-ya uzun müddətdir çatışmayan funksionallıq gətirir. Lambda ifadələri obyektlər kimi dilə funksionallıq gətirir. Bu 100% doğru olmasa da, Lambda ifadələrinin bağlanma olmasa da, oxşar imkanlar təmin etdiyini görə bilərsiniz. Funksional dildə lambda ifadələri funksiyalardır; lakin Java-da lambda ifadələri obyektlərlə təmsil olunur və funksional interfeys adlanan xüsusi obyekt növü ilə əlaqələndirilməlidir. Sonra bunun nə olduğuna baxacağıq. Mario Fusco-nun “Niyə bizə Java-da Lambda İfadəsinə ehtiyacımız var” məqaləsi bütün müasir dillərin niyə bağlanma imkanlarına ehtiyac duyduğunu ətraflı təsvir edir.

Lambda ifadələrinə giriş

Lambda ifadələri anonim funksiyalardır (Java üçün 100% düzgün tərif olmaya bilər, lakin bu, müəyyən aydınlıq gətirir). Sadəcə olaraq, bu bəyannaməsiz bir üsuldur, yəni. giriş dəyişdiriciləri olmadan, dəyəri və adı qaytarır. Bir sözlə, bir üsul yazmağa və dərhal istifadə etməyə imkan verirlər. Birdəfəlik metod çağırışı zamanı xüsusilə faydalıdır, çünki sinif yaratmadan metodu elan etmək və yazmaq üçün lazım olan vaxtı azaldır. Java-da Lambda ifadələri adətən aşağıdakı sintaksisə malikdir (аргументы) -> (тело). Misal üçün:
(арг1, арг2...) -> { тело }

(тип1 арг1, тип2 арг2...) -> { тело }
Aşağıda real Lambda ifadələrinin bəzi nümunələri verilmişdir:
(int a, int b) -> {  return a + b; }

() -> System.out.println("Hello World");

(String s) -> { System.out.println(s); }

() -> 42

() -> { return 3.1415 };

Lambda ifadələrinin strukturu

Lambda ifadələrinin quruluşunu öyrənək:
  • Lambda ifadələrində 0 və ya daha çox giriş parametrləri ola bilər.
  • Parametrlərin növü açıq şəkildə göstərilə bilər və ya kontekstdən əldə edilə bilər. Məsələn ( int a) belə yazıla bilər ( a)
  • Parametrlər mötərizədə verilir və vergüllə ayrılır. Məsələn ( a, b) və ya ( int a, int b) və ya ( String a, int b, float c)
  • Parametrlər yoxdursa, boş mötərizələrdən istifadə etməlisiniz. Misal üçün() -> 42
  • Yalnız bir parametr olduqda, növ açıq şəkildə göstərilməsə, mötərizələr buraxıla bilər. Misal:a -> return a*a
  • Lambda ifadəsinin gövdəsində 0 və ya daha çox ifadə ola bilər.
  • Əgər gövdə tək ifadədən ibarətdirsə, o, əyri mötərizələrə daxil edilə bilməz və qaytarılan dəyər açar sözü olmadan təyin edilə bilər return.
  • Əks halda, əyri mötərizələr tələb olunur (kod bloku) və qaytarma dəyəri açar sözdən istifadə etməklə sonunda göstərilməlidir return(əks halda qaytarma növü void).

Funksional interfeys nədir

Java-da Marker interfeysləri üsullar və ya sahələr elan edilmədən interfeyslərdir. Başqa sözlə, token interfeysləri boş interfeyslərdir. Eynilə, Funksional İnterfeyslər üzərində elan edilmiş yalnız bir mücərrəd metodu olan interfeyslərdir. java.lang.Runnablefunksional interfeys nümunəsidir. Yalnız bir metodu elan edir void run(). Bir interfeys də var ActionListener- həm də funksional. Əvvəllər biz funksional interfeysi həyata keçirən obyektlər yaratmaq üçün anonim siniflərdən istifadə etməli idik. Lambda ifadələri ilə hər şey daha sadə oldu. Hər bir lambda ifadəsi bəzi funksional interfeysə gizli şəkildə bağlana bilər. Məsələn, Runnableaşağıdakı nümunədə göstərildiyi kimi interfeysə istinad yarada bilərsiniz:
Runnable r = () -> System.out.println("hello world");
Funksional interfeys təyin etmədiyimiz zaman bu cür çevirmə həmişə gizli şəkildə həyata keçirilir:
new Thread(
    () -> System.out.println("hello world")
).start();
Yuxarıdakı misalda kompilyator Runnablesinif konstruktorundan interfeysin həyata keçirilməsi kimi avtomatik olaraq lambda ifadəsini yaradır Thread: public Thread(Runnable r) { }. Burada lambda ifadələrinin və müvafiq funksional interfeyslərin bəzi nümunələri verilmişdir:
Consumer<Integer> c = (int x) -> { System.out.println(x) };

BiConsumer<Integer, String> b = (Integer x, String y) -> System.out.println(x + " : " + y);

Predicate<String> p = (String s) -> { s == null };
@FunctionalInterfaceJava Dil Spesifikasiyasına uyğun olaraq Java 8-də əlavə edilmiş annotasiya elan edilmiş interfeysin işlək olub-olmadığını yoxlayır. Bundan əlavə, Java 8 Lambda ifadələri ilə istifadə üçün bir sıra hazır funksional interfeysləri ehtiva edir. @FunctionalInterfaceelan edilmiş interfeys funksional deyilsə, kompilyasiya xətası atacaq. Aşağıda funksional interfeysin müəyyənləşdirilməsinə nümunə verilmişdir:
@FunctionalInterface
public interface WorkerInterface {

    public void doSomeWork();

}
Tərifdən göründüyü kimi, funksional interfeys yalnız bir mücərrəd metoda malik ola bilər. Başqa mücərrəd metod əlavə etməyə çalışsanız, tərtib etmə xətası alacaqsınız. Misal:
@FunctionalInterface
public interface WorkerInterface {

    public void doSomeWork();

    public void doSomeMoreWork();

}
Xəta
Unexpected @FunctionalInterface annotation
    @FunctionalInterface ^ WorkerInterface is not a functional interface multiple
    non-overriding abstract methods found in interface WorkerInterface 1 error
После определения функционального интерфейса, мы можем его использовать и получать все преимущества Lambda-выражений. Пример:// defining a functional interface
@FunctionalInterface
public interface WorkerInterface {

    public void doSomeWork();

}
public class WorkerInterfaceTest {

    public static void execute(WorkerInterface worker) {
        worker.doSomeWork();
    }

    public static void main(String [] args) {

      // calling the doSomeWork method via an anonymous class
      // (classic)
      execute(new WorkerInterface() {
            @Override
            public void doSomeWork() {
               System.out.println("Worker called via an anonymous class");
            }
        });

      // calling the doSomeWork method via Lambda expressions
      // (Java 8 new)
      execute( () -> System.out.println("Worker called via Lambda") );
    }

}
Nəticə:
Worker вызван через анонимный класс
Worker вызван через Lambda
Burada biz öz funksional interfeysimizi müəyyən etdik və lambda ifadəsindən istifadə etdik. Metod execute()lambda ifadələrini arqument kimi qəbul etməyə qadirdir.

Lambda ifadələrinin nümunələri

Lambda ifadələrini başa düşməyin ən yaxşı yolu bir neçə nümunəyə baxmaqdır: Axın Threadiki yolla işə salına bilər:
// Old way:
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello from thread");
    }
}).start();
// New way:
new Thread(
    () -> System.out.println("Hello from thread")
).start();
Java 8-də hadisələrin idarə edilməsi Lambda ifadələri vasitəsilə də həyata keçirilə bilər. Aşağıdakılar ActionListenerUI komponentinə hadisə idarəedicisini əlavə etməyin iki yoludur:
// Old way:
button.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Button pressed. Old way!");
    }
});
// New way:
button.addActionListener( (e) -> {
        System.out.println("Button pressed. Lambda!");
});
Verilmiş massivin bütün elementlərini göstərməyin sadə nümunəsi. Qeyd edək ki, lambda ifadəsini istifadə etməyin birdən çox yolu var. Aşağıda ox sintaksisindən istifadə edərək adi şəkildə lambda ifadəsi yaradırıq və (::)Java 8-də adi metodu lambda ifadəsinə çevirən qoşa nöqtə operatorundan da istifadə edirik:
// Old way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
for(Integer n: list) {
    System.out.println(n);
}
// New way:
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);
list.forEach(n -> System.out.println(n));
// New way using double colon operator ::
list.forEach(System.out::println);
Aşağıdakı misalda biz Predicatetest yaratmaq üçün funksional interfeysdən istifadə edirik və həmin testdən keçən elementləri çap edirik. Bu yolla lambda ifadələrinə məntiq qoya və onun əsasında işlər görə bilərsiniz.
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;

public class Main {

    public static void main(String [] a)  {

        List<Integer> list = Arrays.asList(1, 2, 3, 4, 5, 6, 7);

        System.out.print("Outputs all numbers: ");
        evaluate(list, (n)->true);

        System.out.print("Does not output any number: ");
        evaluate(list, (n)->false);

        System.out.print("Output even numbers: ");
        evaluate(list, (n)-> n%2 == 0 );

        System.out.print("Output odd numbers: ");
        evaluate(list, (n)-> n%2 == 1 );

        System.out.print("Output numbers greater than 5: ");
        evaluate(list, (n)-> n > 5 );

    }

    public static void evaluate(List<Integer> list, Predicate<Integer> predicate) {
        for(Integer n: list)  {
            if(predicate.test(n)) {
                System.out.print(n + " ");
            }
        }
        System.out.println();
    }

}
Nəticə:
Выводит все числа: 1 2 3 4 5 6 7
Не выводит ни одного числа:
Вывод четных чисел: 2 4 6
Вывод нечетных чисел: 1 3 5 7
Вывод чисел больше 5: 6 7
Lambda ifadələri ilə məşğul olmaqla, siyahının hər bir elementinin kvadratını göstərə bilərsiniz. stream()Diqqət yetirin ki, biz müntəzəm siyahını axına çevirmək üçün metoddan istifadə edirik . Java 8 əla sinif təqdim edir Stream( java.util.stream.Stream). Bu, lambda ifadələrindən istifadə edə biləcəyiniz tonlarla faydalı metodları ehtiva edir. Lambda ifadəsini axındakı bütün elementlərə tətbiq edən x -> x*xmetoda ötürürük . Bundan sonra siyahının bütün elementlərini çap etmək üçün map()istifadə edirik .forEach
// Old way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
for(Integer n : list) {
    int x = n * n;
    System.out.println(x);
}
// New way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
list.stream().map((x) -> x*x).forEach(System.out::println);
Siyahı nəzərə alınmaqla, siyahının bütün elementlərinin kvadratlarının cəmini çap etmək lazımdır. Lambda ifadələri sizə yalnız bir kod sətri yazmaqla buna nail olmağa imkan verir. Bu nümunə bükülmə (azaltma) metodundan istifadə edir reduce(). Biz map()hər bir elementi kvadratlaşdırmaq üçün bir üsuldan istifadə edirik və sonra reduce()bütün elementləri bir ədədə yığışdırmaq üçün bir üsuldan istifadə edirik.
// Old way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
int sum = 0;
for(Integer n : list) {
    int x = n * n;
    sum = sum + x;
}
System.out.println(sum);
// New way:
List<Integer> list = Arrays.asList(1,2,3,4,5,6,7);
int sum = list.stream().map(x -> x*x).reduce((x,y) -> x + y).get();
System.out.println(sum);

Lambda ifadələri ilə anonim siniflər arasındakı fərq

Əsas fərq açar sözün istifadəsidir this. Anonim siniflər üçün ' ' açar sözü thisanonim sinfin obyektini, lambda ifadəsində isə ' this' lambda ifadəsinin istifadə olunduğu sinif obyektini bildirir. Başqa bir fərq onların tərtib edilmə üsuludur. privateJava lambda ifadələrini tərtib edir və onları sinif metodlarına çevirir . Bu, dinamik metod bağlaması üçün Java 7-də təqdim edilmiş invokedynamic təlimatından istifadə edir . Tal Weiss öz bloqunda Javanın lambda ifadələrini bayt koduna necə tərtib etdiyini təsvir etdi

Nəticə

Mark Reinhold (Oracle-ın Baş Memarı) Lambda ifadələrini proqramlaşdırma modelində indiyə qədər baş vermiş ən əhəmiyyətli dəyişiklik adlandırdı - hətta generiklərdən daha əhəmiyyətli. O, haqlı olmalıdır, çünki... onlar Java proqramçılarına hər kəsin gözlədiyi funksional proqramlaşdırma dili imkanlarını verir. Virtual genişləndirmə üsulları kimi yeniliklərlə yanaşı, Lambda ifadələri çox keyfiyyətli kod yazmağa imkan verir. Ümid edirəm ki, bu məqalə sizə Java 8-in başlığı altında bir nəzər saldı. Uğurlar :)
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION