JavaRush /Блоги Java /Random-TG /Дар бораи ифодаҳои лямбда дар Java маъмул аст. Бо мисолхо...
Стас Пасинков
Сатҳи
Киев

Дар бораи ифодаҳои лямбда дар Java маъмул аст. Бо мисолхо ва вазифахо. Қисми 2

Дар гурӯҳ нашр шудааст
Ин мақола барои кӣ аст?
  • Барои онхое, ки кисми якуми ин маколаро мехонанд ;

  • Барои онҳое, ки фикр мекунанд, ки Java Core-ро аллакай хуб медонанд, аммо дар бораи ифодаҳои лямбда дар Java тасаввурот надоранд. Ё, шояд, шумо аллакай дар бораи ламбдаҳо чизе шунидаед, аммо бидуни тафсилот.

  • барои онҳое, ки дар бораи ибораҳои лямбда каме фаҳманд, аммо то ҳол аз истифодаи онҳо метарсанд ва ғайриоддӣ ҳастанд.

Дастрасӣ ба тағирёбандаҳои беруна

Оё ин code бо синфи номаълум тартиб дода мешавад?
int counter = 0;
Runnable r = new Runnable() {
    @Override
    public void run() {
        counter++;
    }
};
Не. Тағйирёбанда counterбояд бошад final. Ё ҳатман нест final, аммо дар ҳар сурат он арзиши худро тағир дода наметавонад. Ҳамин принсип дар ифодаҳои лямбда истифода мешавад. Онҳо ба ҳама тағирёбандаҳое, ки ба онҳо "намоёнанд" аз ҷойе, ки эълон карда мешаванд, дастрасӣ доранд. Аммо ламбда набояд онҳоро тағир диҳад (қимати нав таъин кунад). Дуруст аст, ки имкони гузаштан аз ин маҳдудият дар синфҳои номаълум вуҷуд дорад. Фақат як тағирёбандаи навъи истинод ва тағир додани ҳолати дохorи an object кифоя аст. Дар ин ҳолат, худи тағирёбанда ба ҳамон an object ишора мекунад ва дар ин ҳолат шумо метавонед онро ҳамчун final.
final AtomicInteger counter = new AtomicInteger(0);
Runnable r = new Runnable() {
    @Override
    public void run() {
        counter.incrementAndGet();
    }
};
Дар ин ҷо тағирёбандаи мо counterистинод ба an objectи навъи аст AtomicInteger. Ва барои тағир додани ҳолати ин an object, усул истифода мешавад incrementAndGet(). Худи арзиши тағирёбанда ҳангоми иҷрои барнома тағир намеёбад ва ҳамеша ба як an object ишора мекунад, ки ин ба мо имкон медиҳад, ки тағирёбандаро фавран бо калимаи калидӣ эълон кунем final. Мисолҳои якхела, аммо бо ифодаҳои лямбда:
int counter = 0;
Runnable r = () -> counter++;
Он бо ҳамон сабабе, ки вариант бо синфи номаълум тартиб дода мешавад: counterон набояд ҳангоми кор кардани барнома тағир ёбад. Аммо ба ин монанд - ҳама чиз хуб аст:
final AtomicInteger counter = new AtomicInteger(0);
Runnable r = () -> counter.incrementAndGet();
Ин ба усулҳои занг низ дахл дорад. Аз дохor ифодаи лямбда, шумо метавонед на танҳо ба ҳама тағирёбандаҳои "намоён" дастрасӣ пайдо кунед, балки инчунин он усулҳоеро даъват кунед, ки шумо ба онҳо дастрасӣ доред.
public class Main {
    public static void main(String[] args) {
        Runnable runnable = () -> staticMethod();
        new Thread(runnable).start();
    }

    private static void staticMethod() {
        System.out.println("Я - метод staticMethod(), и меня только-что кто-то вызвал!");
    }
}
Гарчанде ки усул staticMethod()хусусӣ аст, он "дастрас" аст, ки онро дар дохor метод даъват кардан мумкин аст main(), бинобар ин занг задан аз дохor лямбда, ки дар метод сохта шудааст, низ дастрас аст main.

Лаҳзаи иҷрои рамзи ифодаи ламбда

Шояд ин савол барои шумо хеле оддӣ ба назар расад, аммо бояд пурсед: code дар дохor ифодаи лямбда кай иҷро мешавад? Дар лаҳзаи офариниш? Ё дар айни замон, ки (ҳанӯз маълум нест) дар куҷо даъват карда мешавад? Санҷиш хеле осон аст.
System.out.println("Запуск программы");

// много всякого разного codeа
// ...

System.out.println("Перед объявлением лямбды");

Runnable runnable = () -> System.out.println("Я - лямбда!");

System.out.println("После объявления лямбды");

// много всякого другого codeа
// ...

System.out.println("Перед передачей лямбды в тред");
new Thread(runnable).start();
Натиҷа дар намоиш:
Запуск программы
Перед объявлением лямбды
После объявления лямбды
Перед передачей лямбды в тред
Я - лямбда!
Мумкин аст, ки рамзи ифодаи лямбда дар ниҳоят, пас аз эҷоди ришта иҷро карда шуд ва танҳо вақте ки раванди иҷрои барнома ба иҷрои воқеии метод расид run(). Ва ҳеҷ гоҳ дар вақти эълони он. Бо эълон кардани ифодаи лямбда, мо танҳо як an objectи намудро эҷод кардем Runnableва рафтори усули онро тавсиф кардем run(). Худи усул хеле дертар ба кор андохта шуд.

Истинодҳои усул?

Ба худи лямбдаҳо бевосита алоқаманд нест, аммо ман фикр мекунам, ки дар ин мақола чанд сухан дар бораи он бигӯям, мантиқӣ мебуд. Биёед бигӯем, ки мо ифодаи лямбда дорем, ки ҳеҷ чизи махсусе намекунад, аммо танҳо ягон усулро даъват мекунад.
x -> System.out.println(x)
Онҳо ба ӯ чизе доданд хва он танҳо ӯро даъват кард System.out.println()ва аз он ҷо гузашт х. Дар ин ҳолат, мо метавонем онро бо истинод ба усули лозима иваз кунем. Монанди ин:
System.out::println
Бале, бе қавс дар охир! Мисоли мукаммал:
List<String> strings = new LinkedList<>();
strings.add("Mother");
strings.add("soap");
strings.add("frame");

strings.forEach(x -> System.out.println(x));
Дар сатри охирин мо усулеро истифода мебарем forEach(), ки an objectи интерфейсро қабул мекунад Consumer. Ин боз як интерфейси функсионалӣ бо танҳо як усул аст void accept(T t). Мувофиқи он мо ифодаи ламбдаро менависем, ки як параметрро мегирад (азбаски он дар худи интерфейс чоп шудааст, мо навъи параметрро нишон намедиҳем, балки нишон медиҳем, ки он номида мешавад х). Дар бадани ифодаи лямбда мо codeро менависем. ки ҳангоми даъват кардани метод иҷро карда мешавад.Дар accept()ин ҷо мо танҳо дар экран он чизеро, ки дар тағирёбанда аст х, нишон медиҳем.Худи усул forEach()аз тамоми элементҳои коллексия мегузарад, Consumerусули an objectи интерфейси ба он додашударо даъват мекунад (ламбда-и мо) accept(), ки он ҳар як элементро аз коллексия мегузарад.Чунон ки ман гуфтам, ин ифодаи lambda аст (танҳо усули дигарро даъват мекунад) мо метавонем бо истинод ба усули лозима иваз кунем.Он гоҳ рамзи мо чунин хоҳад буд:
List<String> strings = new LinkedList<>();
strings.add("Mother");
strings.add("soap");
strings.add("frame");

strings.forEach(System.out::println);
Чизи асосй он аст, ки параметрхои кабулшудаи усулхо (println()ва accept()). Азбаски усул println()метавонад ҳама чизро қабул кунад (он барои ҳама примитивҳо ва барои ҳама an objectҳо изофабор аст), ба ҷои ифодаи лямбда, мо метавонем forEach()танҳо истинод ба метод гузарем println(). Сипас forEach()он ҳар як элементи коллексияро гирифта, мустақиман ба println()Барои онҳое, ки бори аввал бо ин рӯбарӯ мешаванд, лутфан қайд кунед, ки мо ин усулро намехонем (бо нуқтаҳо байни System.out.println()калимаҳо ва дар охири қавс), балки мо истинодро ба худи ин усул мегузорем.
strings.forEach(System.out.println());
мо хатои ҷамъоварӣ хоҳем дошт. Зеро пеш аз занг forEach(), Java мебинад, ки он даъват карда мешавад System.out.println(), мефаҳмад, ки он бармегардад voidва кӯшиш мекунад , ки онро ба an objectи навъи дар он ҷо интизоршуда voidинтиқол диҳад . forEach()Consumer

Синтаксис барои истифодаи истинодҳои метод

Ин хеле содда аст:
  1. Гузаронидани истинод ба усули статикӣNameКласса:: NameСтатическогоМетода?

    public class Main {
        public static void main(String[] args) {
            List<String> strings = new LinkedList<>();
            strings.add("Mother");
            strings.add("soap");
            strings.add("frame");
    
            strings.forEach(Main::staticMethod);
        }
    
        private static void staticMethod(String s) {
            // do something
        }
    }
  2. Гузаронидани истинод ба усули ғайристатикӣ бо истифода аз an objectи мавҷудаNameПеременнойСОбъектом:: method name

    public class Main {
        public static void main(String[] args) {
            List<String> strings = new LinkedList<>();
            strings.add("Mother");
            strings.add("soap");
            strings.add("frame");
    
            Main instance = new Main();
            strings.forEach(instance::nonStaticMethod);
        }
    
        private void nonStaticMethod(String s) {
            // do something
        }
    }
  3. Мо истинодро ба усули ғайристатикӣ бо истифода аз синфе, ки дар он чунин усул татбиқ мешавад, мегузаремNameКласса:: method name

    public class Main {
        public static void main(String[] args) {
            List<User> users = new LinkedList<>();
            users.add(new User("Vasya"));
            users.add(new User("Коля"));
            users.add(new User("Петя"));
    
            users.forEach(User::print);
        }
    
        private static class User {
            private String name;
    
            private User(String name) {
                this.name = name;
            }
    
            private void print() {
                System.out.println(name);
            }
        }
    }
  4. Гузаронидани истинод ба созанда NameКласса::new
    Истифодаи истинодҳои методӣ вақте хеле қулай аст, ки усули тайёр мавҷуд аст, ки шумо аз он комилан қаноатмандед ва шумо мехоҳед онро ҳамчун занги бозпас истифода баред. Дар ин ҳолат, ба ҷои навиштани ифодаи ламбда бо рамзи он усул ё ифодаи ламбда, ки мо ин усулро танҳо меномем, мо танҳо истинод ба он мегузорем. Ҳамааш ҳамин.

Фарқи ҷолиб байни синфи беном ва ифодаи лямбда

Дар синфи беном, калимаи калидӣ thisба an objectи он синфи беном ишора мекунад. Ва агар мо онро thisдар дохor ламбда истифода барем, мо ба an objectи синфи чаҳорчӯба дастрасӣ пайдо мекунем. Дар куҷо мо воқеан ин ифодаро навиштем. Ин аз он сабаб рӯй медиҳад, ки ифодаҳои лямбда ҳангоми тартиб додан ба усули хусусии синфе, ки онҳо навишта мешаванд, мешаванд. Ман истифодаи ин «хусусият»-ро тавсия намедиҳам, зеро он таъсири тараф дорад, ки хилофи принсипҳои барномасозии функсионалӣ мебошад. Аммо ин равиш ба OOP комилан мувофиқ аст. ;)

Ман маълумотро аз куҷо гирифтам ва ё боз чиро хондам

Шарҳҳо
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION