JavaRush /Блоги Java /Random-TG /Ифодаҳои Lambda бо мисолҳо

Ифодаҳои Lambda бо мисолҳо

Дар гурӯҳ нашр шудааст
Java дар ибтидо як забони комилан ба an object нигаронидашуда мебошад. Ба истиснои навъҳои ибтидоӣ, ҳама чиз дар Java an object аст. Ҳатто массивҳо an objectҳо мебошанд. Намунаҳои ҳар як синф an objectҳо мебошанд. Имконияти ягона барои алоҳида муайян кардани функсия вуҷуд надорад (берун аз синф - тақрибан тарҷума. ). Ва ҳеҷ роҳе барои интиқоли усул ба сифати далел ё баргардонидани ҷисми метод дар натиҷаи усули дигар вуҷуд надорад. Чунин аст. Аммо ин пеш аз Java 8 буд. Ифодаҳои ламбда бо мисолҳо - 1Аз айёми Swing-и кӯҳна, зарур буд, ки синфҳои беном навишта шаванд, вақте ки лозим буд, ки баъзе функсияҳоро ба ягон усул интиқол диҳед. Масалан, илова кардани коркарди рӯйдодҳо чунин аст:
someObject.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {

                //Event listener implementation goes here...

            }
        });
Дар ин ҷо мо мехоҳем ба шунавандаи рӯйдодҳои муш як code илова кунем. Мо синфи беномро муайян кардем MouseAdapterва дарҳол аз он an object сохтем. Бо ин роҳ, мо функсияҳои иловагиро ба addMouseListener. Хулоса, тавассути аргументҳо гузаштани як усули оддӣ (функсия) дар Java осон нест. Ин маҳдудият таҳиягарони Java 8-ро маҷбур кард, ки хусусиятеро ба монанди ифодаҳои Lambda ба тавсифи забон илова кунанд.

Чаро Java ба ифодаҳои Lambda лозим аст?

Аз ибтидо забони Java чандон таҳаввул наёфтааст, ба истиснои чизҳое, ки ба монанди Annotations, Generics ва ғайра. Пеш аз ҳама, Java ҳамеша ба an object нигаронидашуда боқӣ мондааст. Пас аз кор кардан бо забонҳои функсионалӣ, ба монанди JavaScript, метавон фаҳмид, ки чӣ гуна Java ба таври қатъӣ ба an object нигаронида шудааст ва сахт чоп карда мешавад. Дар Java функсияҳо лозим нестанд. Худ аз худ онҳоро дар ҷаҳони Java ёфтан мумкин нест. Дар забонҳои барномасозии функсионалӣ функсияҳо ба ҷои аввал меоянд. Онҳо ба худашон вуҷуд доранд. Шумо метавонед онҳоро ба тағирёбандаҳо таъин кунед ва онҳоро тавассути аргументҳо ба дигар функсияҳо гузаронед. JavaScript яке аз беҳтарин намунаҳои забонҳои барномасозии функсионалӣ мебошад. Шумо метавонед мақолаҳои хуберо дар Интернет пайдо кунед, ки манфиатҳои JavaScript-ро ҳамчун забони функсионалӣ муфассал шарҳ медиҳанд. Забонҳои функсионалӣ дорои абзорҳои пурқуввате ба монанди Closure мебошанд, ки нисбат ба усулҳои анъанавии навиштани барномаҳо як қатор бартариҳо фароҳам меоранд. Пӯшидан ин функсияест, ки муҳити ба он замимашуда - ҷадвалест, ки истинодҳоро ба ҳама тағирёбандаҳои ғайримаҳаллии функсия нигоҳ медорад. Дар Java, пӯшиданҳоро тавассути ифодаҳои Lambda тақлид кардан мумкин аст. Албатта, байни бастаҳо ва ифодаҳои Ламбда фарқиятҳо мавҷуданд, на хурд, аммо ифодаҳои лямбда алтернативаи хуб ба басташавӣ мебошанд. Стив Йегге дар блоги масхараомез ва хандовараш тасвир мекунад, ки чӣ тавр ҷаҳони Java ба таври қатъӣ ба исмҳо (an objectҳо, an objectҳо - тахминан тарҷума. ) алоқаманд аст. Агар шумо блоги ӯро нахонда бошед, ман тавсия медиҳам. Вай ба таври хандаовар ва ҷолиб сабаби дақиқи ба Java илова шудани ибораҳои Ламбдаро тавсиф мекунад. Ифодаҳои Lambda ба Java функсияеро меорад, ки муддати тӯлонӣ нопадид буд. Ифодаҳои Lambda ба забон мисли an objectҳо функсионалӣ меоранд. Гарчанде ки ин 100% дуруст нест, шумо мебинед, ки ифодаҳои Lambda, гарчанде ки пӯшида нестанд, қобorятҳои шабеҳро таъмин мекунанд. Дар забони функсионалӣ, ифодаҳои лямбда функсияҳо мебошанд; аммо дар Java, ифодаҳои лямбда аз ҷониби an objectҳо ифода карда мешаванд ва бояд бо як намуди an objectи мушаххас алоқаманд бошанд, ки интерфейси функсионалӣ номида мешавад. Минбаъд мо дида мебароем, ки он чӣ аст. Мақолаи Марио Фуско "Чаро ба мо ифодаи Lambda дар Java лозим аст" муфассал тавсиф мекунад, ки чаро ҳама забонҳои муосир ба қобorятҳои пӯшида ниёз доранд.

Муқаддима ба ифодаҳои Lambda

Ифодаҳои Lambda функсияҳои беном мебошанд (шояд таърифи 100% дуруст барои Java набошад, аммо он каме равшанӣ меорад). Оддӣ карда гӯем, ин усул бидуни эъломия аст, яъне. бе тағирдиҳандаҳои дастрасӣ, баргардонидани арзиш ва ном. Хулоса, онҳо ба шумо имкон медиҳанд, ки усулро нависед ва фавран онро истифода баред. Ин махсусан дар сурати занги усули якдафъаина муфид аст, зеро вақти эълон кардан ва навиштани методро бидуни сохтани синф кам мекунад. Ифодаҳои Lambda дар Java одатан синтаксиси зерин доранд (аргументы) -> (тело). Барои намуна:
(арг1, арг2...) -> { тело }

(тип1 арг1, тип2 арг2...) -> { тело }
Дар зер баъзе мисолҳои ифодаҳои воқеии Lambda оварда шудаанд:
(int a, int b) -> {  return a + b; }

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

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

() -> 42

() -> { return 3.1415 };

Сохтори ифодаҳои Ламбда

Биёед сохтори ифодаҳои лямбдаро омӯзем:
  • Ифодаҳои лямбда метавонанд 0 ё бештар параметрҳои вуруд дошта бошанд.
  • Навъи параметрҳоро метавон ба таври возеҳ муайян кард ё аз контекст гирифтан мумкин аст. Масалан ( int a) метавонад чунин навишт ( a)
  • Параметрҳо дар қавс гирифта шуда, бо вергул ҷудо карда мешаванд. Масалан ( a, b) ё ( int a, int b) ё ( String a, int b, float c)
  • Агар ягон параметр мавҷуд набошад, пас шумо бояд қавсҳои холиро истифода баред. Барои намуна() -> 42
  • Вақте ки танҳо як параметр мавҷуд аст, агар намуд ба таври возеҳ нишон дода нашавад, қавсҳоро партофтан мумкин аст. Мисол:a -> return a*a
  • Ҷисми ифодаи Ламбда метавонад 0 ё зиёда ифодаҳоро дар бар гирад.
  • Агар бадан аз як изҳорот иборат бошад, он метавонад ба қавсҳои ҷингила дохил карда нашавад ва арзиши баргардонида метавонад бидуни калимаи калидӣ муайян карда шавад return.
  • Дар акси ҳол, қавсҳои ҷингила талаб карда мешаванд (блоки code) ва арзиши баргардонидан бояд дар охир бо истифода аз калимаи калидӣ муайян карда шавад return(дар акси ҳол навъи бозгашт void).

Интерфейси функсионалӣ чист

Дар Java, интерфейсҳои Marker интерфейсҳое мебошанд, ки усулҳо ё майдонҳоро эълон намекунанд. Ба ибораи дигар, интерфейсҳои токен интерфейсҳои холӣ мебошанд. Ба ҳамин монанд, Интерфейсҳои функсионалӣ интерфейсҳое мебошанд, ки дар он танҳо як усули абстрактӣ эълон шудааст. java.lang.Runnableнамунаи интерфейси функсионалӣ мебошад. Он танҳо як усулро эълон мекунад void run(). Инчунин интерфейс мавҷуд аст ActionListener- инчунин функсионалӣ. Пештар, мо бояд барои сохтани an objectҳое, ки интерфейси функсионалӣ амалӣ мекунанд, синфҳои беномро истифода мебурдем. Бо ифодаҳои Lambda, ҳама чиз соддатар шуд. Ҳар як ифодаи ламбда метавонад ба таври ғайримустақим ба баъзе интерфейси функсионалӣ пайваст карда шавад. Масалан, шумо метавонед истинод ба Runnableинтерфейс эҷод кунед, тавре ки дар мисоли зерин нишон дода шудааст:
Runnable r = () -> System.out.println("hello world");
Ин гуна табдилдиҳӣ ҳамеша ба таври ғайримустақим анҷом дода мешавад, вақте ки мо интерфейси функсионалӣ муайян накунем:
new Thread(
    () -> System.out.println("hello world")
).start();
Дар мисоли боло, компилятор ба таври худкор ифодаи ламбдаро ҳамчун амалисозии Runnableинтерфейс аз созандаи синф эҷод мекунад Thread: public Thread(Runnable r) { }. Инҳоянд чанд намунаи ифодаҳои ламбда ва интерфейсҳои функсионалии мувофиқ:
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 };
Эзоҳе @FunctionalInterface, ки дар Java 8 мувофиқи Мушаххасоти забони Java илова карда шудааст, тафтиш мекунад, ки интерфейси эълоншуда функсионалӣ аст ё не. Илова бар ин, Java 8 як қатор интерфейсҳои функсионалии тайёрро барои истифода бо ифодаҳои Lambda дар бар мегирад. @FunctionalInterfaceагар интерфейси эълоншуда корношоям набошад, хатогии тартиб медиҳад. Дар зер намунаи муайян кардани интерфейси функсионалӣ оварда шудааст:
@FunctionalInterface
public interface WorkerInterface {

    public void doSomeWork();

}
Тавре ки аз таъриф бармеояд, интерфейси функсионалӣ метавонад танҳо як усули абстрактӣ дошта бошад. Агар шумо кӯшиш кунед, ки усули абстрактии дигарро илова кунед, шумо хатои ҷамъоварӣ мегиред. Мисол:
@FunctionalInterface
public interface WorkerInterface {

    public void doSomeWork();

    public void doSomeMoreWork();

}
Хатогӣ
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") );
    }

}
Хулоса:
Worker вызван через анонимный класс
Worker вызван через Lambda
Дар ин ҷо мо интерфейси функсионалии худро муайян кардем ва ифодаи ламбдаро истифода бурдем. Ин усул execute()қодир аст ифодаҳои лямбдаро ҳамчун далел қабул кунад.

Намунаҳои ифодаҳои Lambda

Беҳтарин роҳи фаҳмидани ибораҳои Lambda ин дидан ба чанд мисол аст: Ҷараёнро Threadбо ду роҳ оғоз кардан мумкин аст:
// 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 инчунин метавонад тавассути ифодаҳои Lambda анҷом дода шавад. Дар зер ду роҳи илова кардани коркардкунандаи рӯйдод ActionListenerба ҷузъи UI мавҷуданд:
// 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!");
});
Мисоли оддии намоиши ҳамаи элементҳои массиви додашуда. Дар хотир доред, ки зиёда аз як роҳи истифодаи ифодаи ламбда вуҷуд дорад. Дар зер мо бо истифода аз синтаксиси тир ифодаи лямбдаро ба таври муқаррарӣ эҷод мекунем ва инчунин оператори дукаратаи дукаратаро истифода мебарем (::), ки дар Java 8 усули муқаррариро ба ифодаи ламбда табдил медиҳад:
// 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);
Дар мисоли зерин, мо интерфейси функсионалӣ Predicateбарои сохтани санҷиш ва чопи ашёҳоеро, ки аз ин санҷиш мегузаранд, истифода мебарем. Бо ин роҳ шумо метавонед мантиқро ба ифодаҳои лямбда ҷойгир кунед ва дар асоси он корҳоро анҷом диҳед.
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();
    }

}
Хулоса:
Выводит все числа: 1 2 3 4 5 6 7
Не выводит ни одного числа:
Вывод четных чисел: 2 4 6
Вывод нечетных чисел: 1 3 5 7
Вывод чисел больше 5: 6 7
Бо истифода аз ифодаҳои Lambda, шумо метавонед квадрати ҳар як унсури рӯйхатро нишон диҳед. Аҳамият диҳед, ки мо усули stream()табдил додани рӯйхати муқаррариро ба ҷараён истифода мебарем. Java 8 як синфи олиро пешкаш мекунад Stream( java.util.stream.Stream). Он дорои даҳҳо усулҳои муфид аст, ки шумо метавонед бо ифодаҳои лямбда истифода баред. Мо ифодаи лямбдаро x -> x*xба усули мегузарем map(), ки онро ба ҳама унсурҳои ҷараён татбиқ мекунад. Пас аз он мо 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);
Бо назардошти рӯйхат, шумо бояд маблағи квадратҳои ҳамаи элементҳои рӯйхатро чоп кунед. Ифодаҳои Lambda ба шумо имкон медиҳанд, ки бо навиштани як сатри code ба ин ноил шавед. Ин мисол усули конволютсионӣ (камкунӣ) -ро истифода мебарад reduce(). Мо усули map()мураббаъ кардани ҳар як элементро истифода мебарем ва сипас усулеро истифода мебарем, reduce()ки ҳамаи элементҳоро ба як адад ҷамъ кунед.
// 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 ва синфҳои номаълум

Фарқи асосӣ истифодаи калимаи калидӣ мебошад this. Барои синфҳои беном, калимаи калидии ' ' thisan objectи синфи беномро ифода мекунад, дар ҳоле ки дар ифодаи лямбда, ' this' an objectи синферо, ки дар он ифодаи лямбда истифода мешавад, ифода мекунад. Фарқияти дигар ин тарзи тартиб додани онҳост. Java ифодаҳои лямбдаро тартиб медиҳад ва онҳоро ба privateусулҳои синф табдил медиҳад. Ин дастури invokedynamic -ро истифода мебарад , ки дар Java 7 барои пайвасткунии усули динамикӣ ҷорӣ шудааст. Тал Вайс дар блоги худ тавсиф кард, ки чӣ тавр Java ифодаҳои лямбдаро ба byte code тартиб медиҳад

Хулоса

Марк Рейнхолд (Сармеъмори Oracle) ифодаҳои Lambda-ро муҳимтарин тағирот дар модели барномасозӣ номид, ки то ҳол ба вуқӯъ пайвастааст - ҳатто муҳимтар аз генерикҳо. Ӯ бояд дуруст бошад, зеро... онҳо ба барномасозони Java имкониятҳои функсионалии забони барномасозиро медиҳанд, ки ҳама интизори он буданд. Дар баробари навовариҳо ба монанди усулҳои васеъшавии виртуалӣ, ифодаҳои Lambda ба шумо имкон медиҳанд, ки рамзи хеле баландсифат нависед. Ман умедворам, ки ин мақола ба шумо дар зери сарпӯши Java 8 нигоҳ кард. Барори кор :)
Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION