JavaRush /Java Blog /Random-TK /Java-da lambda aňlatmalary hakda meşhur. Mysallar we mese...

Java-da lambda aňlatmalary hakda meşhur. Mysallar we meseleler bilen. 1-nji bölüm

Toparda çap edildi
Bu makala kim üçin?
  • Java Core-ni eýýäm gowy bilýärler öýdýän, ýöne Java-da lambda aňlatmalary hakda pikirem ýoklar üçin. Ora-da, belki, lambdalar hakda bir zat eşitdiňiz, ýöne jikme-jikliksiz.
  • lambda aňlatmalaryna belli bir derejede düşünýän, ýöne olary ulanmakdan gorkýan we adaty däl adamlar üçin.
Bu kategoriýalaryň birine girmeseňiz, bu makalany içgysgynç, nädogry we umuman “salkyn däl” diýip bilersiňiz. Bu ýagdaýda ýa-da geçip bilersiňiz, ýa-da mowzugy gowy bilýän bolsaňyz, makalany nädip gowulaşdyryp ýa-da üstüni ýetirip boljakdygyny teswirlerde teklip ediň. Material hiç hili akademiki gymmaty talap etmeýär, täzelik az. Has dogrusy, tersine: onda çylşyrymly (käbir zatlar üçin) mümkin boldugyça ýönekeý suratlandyrmaga synanyşaryn. Akymy düşündirmek haýyşy bilen ýazmak maňa ylham berdi. Bu barada pikirlenip, lambda sözlerine düşünmän, “akymlar” baradaky käbir mysallarymyň düşnüksiz boljakdygyna karar berdim. Geliň, lambdalardan başlalyň. Java-da lambda aňlatmalary hakda meşhur.  Mysallar we meseleler bilen.  1-nji bölümBu makala düşünmek üçin haýsy bilimler talap edilýär:
  1. Obýekte gönükdirilen programmirleme (mundan beýläk OOP diýilýär) düşünmek, ýagny:
    • synplaryň we obýektleriň nämedigini, olaryň arasyndaky tapawudyň nämedigini bilmek;
    • interfeýsleriň nämedigini, synplardan nähili tapawutlanýandyklaryny, olaryň arasyndaky baglanyşyk nämedigini (interfeýsler we synplar) bilmek;
    • usulyň nämedigini, ony nädip atlandyrmalydygyny, abstrakt usulyň nämedigini (ýa-da durmuşa geçirmezden usul), usulyň parametrleriniň / argumentleriniň nämedigini, olary nädip geçirmelidigini bilmek;
    • üýtgedijilere, statiki usullara / üýtgeýänlere, soňky usullara / üýtgeýänlere girmek;
    • miras (synplar, interfeýsler, interfeýsleriň köp mirasy).
  2. Java ýadrosyny bilmek: umumylyklar, ýygyndylar (sanawlar), sapaklar.
Bolýar, başlalyň.

Biraz taryh

Lambda aňlatmalary Java-a funksional programmirlemekden we ol ýerde matematikadan geldi. 20-nji asyryň ortalarynda Amerikada belli bir Alonzo kilisesi Prinston uniwersitetinde matematika we her dürli abstraktlary gowy görýärdi. Ilkibaşda käbir abstrakt pikirleriň toplumy bolan we programmirleme bilen hiç hili baglanyşygy bolmadyk lambda hasaplamasyny oýlap tapan Alonzo buthanasydy. Şol bir wagtyň özünde Alan Týuring we Jon fon Neumann ýaly matematikler şol bir Prinston uniwersitetinde işlediler. Hemme zat bir ýere jemlendi: Ybadathana lambda hasaplaýyş ulgamyny döretdi, Týuring häzirki wagtda “Týuring maşyny” diýlip atlandyrylýan abstrakt hasaplaýyş maşynyny döretdi. Won Neumann häzirki zaman kompýuterleriniň esasyny emele getirýän (we häzirki wagtda “fon Neumann arhitekturasy” diýlip atlandyrylýar) kompýuterleriň arhitekturasynyň diagrammasyny teklip etdi. Şol döwürde Alonzo kilisesiniň pikirleri kärdeşleriniň işi ýaly meşhur bolmady (“arassa” matematika ugrundan başga). Şeýle-de bolsa, sähelçe wagt geçensoň, belli bir Jon Makkarti (şol bir wagtyň özünde Prinston uniwersitetini gutaran, Massaçusets Tehnologiýa Institutynyň işgäri) ​​ýygnagyň ideýalary bilen gyzyklandy. Olara esaslanyp, 1958-nji ýylda ilkinji işleýän programmirleme dili Lisp döretdi. 58 ýyldan soň, funksional programmirleme ideýalary Java-a 8-nji san hökmünde ýaýrady. Hatda 70 ýyl hem geçmedi ... Aslynda bu matematiki ideýany iş ýüzünde ulanmak üçin iň uzyn döwür däl.

Esasy manysy

Lambda aňlatmasy şeýle funksiýa. Muny Java-da adaty usul diýip pikir edip bilersiňiz, ýeke-täk tapawut, argument hökmünde beýleki usullara geçirilip bilner. Hawa, diňe sanlary, setirleri we pişikleri usullara däl, eýsem beýleki usullara-da geçirmek mümkin boldy! Bu bize haçan gerek bolup biler? Mysal üçin, käbir jaňdan geçmek islesek. Oňa geçýän başga bir usuly çagyryp bilmek üçin çagyrýan usulymyz gerek. .Agny, käbir halatlarda bir jaňy, beýlekisinde bolsa yzyna ibermek mümkinçiligimiz bolar. Çagyryşlarymyzy kabul etjek usulymyz olara jaň ederdi. Simpleönekeý mysal tertiplemekdir. Şuňa meňzeş bir hili çylşyrymly sortlaşdyrma ýazýarys diýeliň:
public void mySuperSort() {
    // ... do something here
    if(compare(obj1, obj2) > 0)
    // ... and here we do something
}
Nirede, ifusuly diýýäris compare(), deňeşdiren iki zadymyzy şol ýerden geçirýäris we bu obýektleriň haýsysynyň “uludygyny” bilmek isleýäris. “Has köp” bolan zady “kiçi” biriniň öňünde goýarys. Sitatlarda “has köp” ýazdym, sebäbi diňe bir ýokary galmak bilen çäklenmän, aşak düşýän tertipde hem tertipleşdirip boljak uniwersal usuly ýazýarys (bu ýagdaýda “has köp” aslynda has kiçi obýekt bolar we tersine) . Düzgüni nädip tertipleşdirmek isleýändigimizi kesgitlemek üçin, nämüçindir ony özümize geçirmeli mySuperSort(). Bu ýagdaýda, usuly çagyrylanda nädip "gözegçilik" edip bileris. Elbetde, ýokarlanmak we aşak düşmek tertibi boýunça tertiplemek mySuperSortAsc()üçin iki aýratyn usul ýazyp bilersiňiz. mySuperSortDesc()Ora-da usulyň içinde käbir parametrleri geçiriň (mysal üçin, booleanýokarlanýan truetertipde we falseaşak düşýän tertipde). Someöne ýönekeý gurluşy däl-de, mysal üçin, setir massiwleriniň sanawyny tertiplemek islesek näme etmeli? Usulymyz mySuperSort()bu setir massiwlerini nädip tertipleşdirmelidigini nädip biler? Ölçeg üçin? Sözleriň umumy uzynlygy boýunça? Belki, massiwdäki birinji hatara baglylykda elipbiý boýunça? Someöne käbir ýagdaýlarda massiwleriň sanawyny massiwiň ululygyna, başga bir ýagdaýda bolsa sözleriň umumy uzynlygyna görä tertipleşdirmeli bolsa näme etmeli? Meniň pikirimçe, deňeşdirijiler hakda eýýäm eşitdiňiz we şeýle ýagdaýlarda diňe tertipleşdiriş usulymyza deňeşdirmek obýektini geçirýäris, onda tertipleşdirmek isleýän düzgünlerimizi beýan edýäris. Adaty usul sort()şol bir prinsipde durmuşa geçirilýändigi sebäpli, mySuperSort()mysallarda men adaty usuly ulanaryn sort().
String[] array1 = {"Mother", "soap", "frame"};
String[] array2 = {"I", "Very", "I love", "java"};
String[] array3 = {"world", "work", "May"};

List<String[]> arrays = new ArrayList<>();
arrays.add(array1);
arrays.add(array2);
arrays.add(array3);

Comparator<String[]> sortByLength = new Comparator<String[]>() {
    @Override
    public int compare(String[] o1, String[] o2) {
        return o1.length - o2.length;
    }
};

Comparator<String[]> sortByWordsLength = new Comparator<String[]>() {
    @Override
    public int compare(String[] o1, String[] o2) {
        int length1 = 0;
        int length2 = 0;
        for (String s : o1) {
            length1 += s.length();
        }
        for (String s : o2) {
            length2 += s.length();
        }
        return length1 - length2;
    }
};

arrays.sort(sortByLength);
Netije:
  1. Eje çarçuwany ýuwdy
  2. parahatçylyk Zähmet çekip biler
  3. Men java gaty gowy görýärin
Bu ýerde massiwler her massiwdäki sözleriň sany boýunça tertiplenýär. Az sözli massiw “kiçi” hasaplanýar. Şonuň üçin başynda gelýär. Has köp söz bar ýerinde “has köp” hasaplanýar we ahyrynda gutarýar. sort()Usula başga bir deňeşdiriji geçirsek , (sortByWordsLength)netije başgaça bolar:
  1. parahatçylyk Zähmet çekip biler
  2. Eje çarçuwany ýuwdy
  3. Men java gaty gowy görýärin
Indi massiwler şeýle massiwdäki sözleriň umumy sany boýunça tertiplenýär. Birinji ýagdaýda 10 harp, ikinjisinde 12 we üçünji 15 harp bar. Diňe bir deňeşdiriji ulansak, onuň üçin aýratyn üýtgeýji döredip bilmeris, diňe bir ady belli bolmadyk synp obýektini döredip bileris usuly çagyrmagyň wagty sort(). Munuň ýaly:
String[] array1 = {"Mother", "soap", "frame"};
String[] array2 = {"I", "Very", "I love", "java"};
String[] array3 = {"world", "work", "May"};

List<String[]> arrays = new ArrayList<>();
arrays.add(array1);
arrays.add(array2);
arrays.add(array3);

arrays.sort(new Comparator<String[]>() {
    @Override
    public int compare(String[] o1, String[] o2) {
        return o1.length - o2.length;
    }
});
Netije birinji ýagdaýdaky ýaly bolar. 1-nji wezipe . Bu mysaly massiwdäki sözleriň sanynyň artýan tertibinde däl-de, aşak düşýän tertipde tertipleşdirmek üçin täzeden ýazyň. Bularyň hemmesini eýýäm bilýäris. Obýektleri usullara nädip geçirmelidigini bilýäris, şu wagt ýa-da şol obýekti häzirki wagtda nämä gerekdigimize baglylykda bir usula geçirip bileris we şeýle obýekti geçen usulyň içinde durmuşa geçirmegi ýazan usulymyz atlandyrylar. . Sorag ýüze çykýar: lambda aňlatmalarynyň munuň bilen näme baglanyşygy bar? Lambdanyň takyk bir usuly öz içine alýan jisimdigini göz öňünde tutsak. Usul obýektine meňzeýär. Bir obýekt bilen örtülen usul. Olarda diňe birneme üýtgeşik sintaksis bar (ýöne has soňrak). Geliň, bu ýazga başga bir göz aýlalyň
arrays.sort(new Comparator<String[]>() {
    @Override
    public int compare(String[] o1, String[] o2) {
        return o1.length - o2.length;
    }
});
Bu ýerde sanawymyzy alýarys arrayswe onuň usulyna jaň edýäris sort(), şol ýerde bir usul bilen deňeşdiriji obýekti geçýäris compare()(onuň näme diýilmeginiň ähmiýeti ýok, sebäbi bu obýektdäki ýeke-täk zat, biz ony sypdyrmarys). Bu usul iki parametr alýar, indiki bilen işleýäris. IntelliJ IDEA- da işleýän bolsaňyz , bu kody ep-esli gysgaltmak üçin size nähili hödürleýändigini gören bolsaňyz gerek:
arrays.sort((o1, o2) -> o1.length - o2.length);
Ine, alty setir bir gysga hatara öwrüldi. 6 setir bir gysga hatara gaýtadan ýazyldy. Bir zat ýitdi, ýöne möhüm bir zadyň ýitip gitmändigine kepil geçýärin we bu kod näbelli synp bilen edil işleýär. 2-nji wezipe . Lambdalary ulanyp, 1-nji meseläniň çözgüdini nädip täzeden ýazmalydygyny kesgitläň (iň soňky ýol hökmünde IntelliJ IDEA-dan näbelli synpyňyzy lambda öwürmegini haýyş ediň).

Interfeýsler barada gürleşeliň

Esasan, interfeýs diňe abstrakt usullaryň sanawydyr. Synp döredenimizde we haýsydyr bir interfeýsi durmuşa geçirjekdigini aýdanymyzda, synpymyzda interfeýsde görkezilen usullaryň ýerine ýetirilişini ýazmalydyrys (ýa-da iň soňky ýol hökmünde ony ýazman, synpy abstrakt etmeli) ). Köp dürli usully interfeýsler bar (mysal üçin List), diňe bir usul bilen interfeýsler bar (mysal üçin, şol bir deňeşdiriji ýa-da işledip bolýan). Asla ýekeje usulsyz interfeýsler bar (marker interfeýsleri diýilýär, mysal üçin Serializable). Diňe bir usuly bolan şol interfeýslere funksional interfeýsler hem diýilýär . Java 8-de hatda ýörite @FunctionalInterface düşündiriş bilen bellik edilýär . Lambda aňlatmalary bilen ulanmak üçin amatly bir usul bilen interfeýslerdir. Aboveokarda aýdyşym ýaly, lambda aňlatmasy bir obýekte örtülen usuldyr. Şeýle obýekti bir ýerden geçirenimizde, aslynda bu ýekeje usuly geçýäris. Görnüşi ýaly, bu usulyň näme diýilmegi biziň üçin möhüm däl. Biziň üçin möhüm zat, bu usulyň alýan parametrleri we aslynda usul kodunyň özi. Aslynda lambda aňlatmasy. funksional interfeýsi durmuşa geçirmek. Bir usul bilen interfeýsi gören ýerimizde, lambda ulanyp, şeýle anonim synpy täzeden ýazyp biljekdigimizi aňladýar. Eger interfeýsde birden köp / az usul bar bolsa, lambda aňlatmasy bize laýyk gelmez, biz näbelli synpy, hatda adaty bir usuly ulanarys. Lambdalary gazmagyň wagty geldi. :)

Sintaksis

Umumy sintaksis şuňa meňzeş bir zat:
(параметры) -> {тело метода}
.Agny, içindäki gabygyň usuly parametrleri, “ok” (bular yzly-yzyna iki simwol: minus we ondan uly), şondan soň usulyň göwrümi hemişe bolşy ýaly egri ýaýlarda bolýar. Usul beýan edilende parametrler interfeýsde görkezilenlere gabat gelýär. Üýtgeýjileriň görnüşini düzüji anyk kesgitläp bilýän bolsa (biziň ýagdaýymyzda, setirleriň massiwleri bilen işleýändigimiz belli, sebäbi Listsetirleriň massiwleri bilen takyk ýazylýar), üýtgeýänleriň görnüşi String[]hökman däl ýazylmaly.
Ynanmasaňyz, görnüşini görkeziň we IDEA zerur bolmasa ony çal reňkde görkezer.
Mysal üçin, Oracle gollanmasynda has köp okap bilersiňiz . Muňa "maksatly ýazmak" diýilýär . Üýtgeýjilere interfeýsde görkezilenler hökman däl, islendik atlar berilip bilner. Parametrler ýok bolsa, diňe gabygyň. Diňe bir parametr bar bolsa, diňe dakylýan üýtgeýän at. Parametrleri düzdük, indi lambda aňlatmasynyň bedeni hakda. Egri ýaýlaryň içinde adaty usul ýaly kod ýazyň. Bütin koduňyz diňe bir setirden ybarat bolsa, asla egri ýaýlary ýazmaly dälsiňiz (ifs we aýlawlar ýaly). Lambda bir zat gaýtaryp berse, ýöne bedeni bir setirden ybarat bolsa, returnýazmak hökman däl. Youöne egri ýaýlaryňyz bar bolsa, adaty usulda bolşy ýaly, aç-açan ýazmaly return.

Mysallar

Mysal 1.
() -> {}
Iň ýönekeý wariant. Iň manysyz bolsa :). Sebäbi hiç zat edenok. Mysal 2.
() -> ""
Şeýle hem gyzykly wariant. Hiç zady kabul etmeýär we boş setiri yzyna gaýtaryp berýär ( returngereksiz hökmünde goýulýar). Edil şol, ýöne return:
() -> {
    return "";
}
Mysal 3. Lambdas ulanyp dünýä salam
() -> System.out.println("Hello world!")
returnHiç zat almaýar, hiç zat gaýtaryp bermeýär ( jaňdan öň goýup bilmeris System.out.println(), sebäbi usuldaky gaýdyp beriş görnüşi println() — void)ekranda diňe bir ýazgy görkezýär. Interfeýsi durmuşa geçirmek üçin amatly Runnable. Şol mysal has doly:
public class Main {
    public static void main(String[] args) {
        new Thread(() -> System.out.println("Hello world!")).start();
    }
}
Ora-da şuňa meňzeş:
public class Main {
    public static void main(String[] args) {
        Thread t = new Thread(() -> System.out.println("Hello world!"));
        t.start();
    }
}
Ora-da hatda lambda aňlatmasyny görnüş görnüşi hökmünde saklap Runnable, soň bolsa konstruktora geçirip bileris thread’а:
public class Main {
    public static void main(String[] args) {
        Runnable runnable = () -> System.out.println("Hello world!");
        Thread t = new Thread(runnable);
        t.start();
    }
}
Lambda aňlatmasyny üýtgeýjä tygşytlamak pursatyna has içgin seredeliň. Interfeýs Runnable, obýektleriniň usuly bolmalydygyny aýdýar public void run(). Interfeýs boýunça işletmek usuly hiç zady parametr hökmünde kabul etmeýär. Ol hiç zady yzyna gaýtarmaýar (void). Şonuň üçin bu görnüşde ýazylanda hiç zady kabul etmeýän ýa-da yzyna gaýtarmaýan haýsydyr bir usul bilen bir obýekt dörediler. run()Interfeýsdäki usula gaty laýyk gelýär Runnable. Şonuň üçin bu lambda aňlatmasyny ýaly üýtgeýjä goýup bildik Runnable. Mysal 4
() -> 42
Againene-de hiç zady kabul etmeýär, ýöne 42 belgisini gaýtaryp berýär. Bu lambda aňlatmasy üýtgeýän görnüşde ýerleşdirilip bilner Callable, sebäbi bu interfeýs diňe şuňa meňzeş bir usuly kesgitleýär:
V call(),
Vyzyna gaýtaryş bahasynyň görnüşi nirede (biziň ýagdaýymyzda ) int. Şoňa görä, şeýle lambda aňlatmasyny aşakdaky ýaly saklap bileris:
Callable<Integer> c = () -> 42;
Mysal 5. Lambda birnäçe setirde
() -> {
    String[] helloWorld = {"Hello", "world!"};
    System.out.println(helloWorld[0]);
    System.out.println(helloWorld[1]);
}
voidAgainene-de, bu parametrleri we gaýdyp geliş görnüşi (ýoklugy sebäpli return) lambda aňlatmasydyr . Mysal 6
x -> x
Bu ýerde bir zady üýtgeýjä alyp х, yzyna gaýtaryp berýäris. Diňe bir parametr kabul edilen bolsa, töweregindäki gabygyň ýazylmagynyň zerur däldigini ýadyňyzdan çykarmaň. Edil şol bir, ýöne ýaý bilen:
(x) -> x
Ine, aç-açan bir wariant return:
x -> {
    return x;
}
Ora-da şuňa meňzeş, ýaý bilen we return:
(x) -> {
    return x;
}
Ora-da görnüşini aç-açan görkezmek bilen (we şoňa görä, gabygy bilen):
(int x) -> x
Mysal 7
x -> ++x
Biz kabul edýäris хwe gaýtaryp berýäris, ýöne 1has köp zat üçin. Şeýle hem täzeden ýazyp bilersiňiz:
x -> x + 1
Iki ýagdaýda-da parametr, usul göwrümi we söz töweregindäki gabygy görkezmeýäris return, sebäbi bu zerur däl. Garaşan we gaýdyp gelýän opsiýalar 6-njy mysalda düşündirilýär. 8-nji mysal
(x, y) -> x % y
Käbirlerini kabul edýäris хwe уbölünişigiň galan bölegini xyzyna gaýtaryp berýäris y. Parametrleriň töweregindäki berkitmeler bu ýerde eýýäm talap edilýär. Diňe bir parametr bar bolanda islege bagly däl. Görnüşlerini aç-açan görkezmek bilen:
(double x, int y) -> x % y
Mysal 9
(Cat cat, String name, int age) -> {
    cat.setName(name);
    cat.setAge(age);
}
Pişik obýektini, ady we bitewi ýaşy bolan setiri kabul edýäris. Usulyň özünde, geçen ady we ýaşy Pişige belledik. Üýtgeýjimiz catsalgylanma görnüşi bolansoň, lambda aňlatmasynyň daşyndaky Pişik obýekti üýtgär (adyny we ýaşyny alar). Meňzeş lambda ulanýan birneme çylşyrymly wersiýa:
public class Main {
    public static void main(String[] args) {
        // create a cat and print to the screen to make sure it's "blank"
        Cat myCat = new Cat();
        System.out.println(myCat);

        // create lambda
        Settable<Cat> s = (obj, name, age) -> {
            obj.setName(name);
            obj.setAge(age);
        };

        // call the method, to which we pass the cat and the lambda
        changeEntity(myCat, s);
        // display on the screen and see that the state of the cat has changed (has a name and age)
        System.out.println(myCat);
    }

    private static <T extends WithNameAndAge>  void changeEntity(T entity, Settable<T> s) {
        s.set(entity, "Murzik", 3);
    }
}

interface WithNameAndAge {
    void setName(String name);
    void setAge(int age);
}

interface Settable<C extends WithNameAndAge> {
    void set(C entity, String name, int age);
}

class Cat implements WithNameAndAge {
    private String name;
    private int age;

    @Override
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
Netije: Pişik {name = 'null', ýaş = 0} Pişik {name = 'Murzik', ýaş = 3 see Görşüňiz ýaly, ilki bilen Pişik obýektiniň bir ýagdaýy bardy, ýöne lambda aňlatmasyny ulanandan soň döwlet üýtgedi . Lambda aňlatmalary generika bilen gowy işleýär. DogMysal üçin, bu hem durmuşa geçirjek synp döretmeli bolsa WithNameAndAge, main()lambda aňlatmasyny düýbünden üýtgetmän, It bilen şol bir amallary edip bileris. 3-nji wezipe . San alýan we Boolean bahasyny yzyna gaýtarýan usul bilen işleýän interfeýs ýazyň. Şeýle interfeýsiň ýerine ýetirilişini lambda aňlatmasy görnüşinde ýazyň, trueeger geçen san 13-e bölünmese, yzyna gaýtarylar . 4-nji wezipe . Iki setir alýan we şol bir setiri yzyna gaýtarýan usul bilen funksional interfeýs ýazyň. Şeýle interfeýsiň iň uzyn setirini gaýtaryp berýän lambda görnüşinde ýazyň. 5-nji wezipe . Üç bölek sanlary kabul edýän usul bilen işleýän interfeýsi ýazyň: awe bşol cbir fraksiýa belgisini yzyna gaýtaryp berýär. Şeýle interfeýsiň ýerine ýetirilişini kemsidiji gaýtaryp berýän lambda aňlatmasy görnüşinde ýazyň. Kim ýatdan çykardy, D = b ^ 2 - 4ac . 6-njy wezipe . 5-nji ýumuşdan işleýän interfeýsi ulanyp, amalyň netijesini görkezýän lambda aňlatmasyny ýazyň a * b^c. Java-da lambda aňlatmalary hakda meşhur. Mysallar we meseleler bilen. 2-nji bölüm.
Teswirler
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION