JavaRush /Blog Jawa /Random-JV /Ekspresi Lambda kanthi conto

Ekspresi Lambda kanthi conto

Diterbitake ing grup
Basa Jawa wiwitane minangka basa sing berorientasi obyek. Kajaba jinis primitif, kabeh ing Jawa minangka obyek. Malah array minangka obyek. Instance saben kelas minangka obyek. Ora ana kamungkinan kanggo nemtokake fungsi kanthi kapisah (ing njaba kelas - kira-kira transl. ). Lan ora ana cara kanggo ngliwati metode minangka argumen utawa ngasilake badan metode minangka asil saka metode liyane. Kaya ngono. Nanging iki sadurunge Jawa 8. Ekspresi Lambda kanthi conto - 1Wiwit dina Swing lawas apik, iku perlu kanggo nulis kelas anonim nalika iku perlu kanggo pass sawetara fungsi kanggo sawetara cara. Contone, iki katon kaya nambah panangan acara:
someObject.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {

                //Event listener implementation goes here...

            }
        });
Ing kene kita pengin nambah sawetara kode menyang pamiyarsa acara mouse. Kita nemtokake kelas anonim MouseAdapterlan langsung nggawe obyek saka iku. Kanthi cara iki, kita wis ngliwati fungsi tambahan menyang addMouseListener. Cekakipun, boten gampil nglangkungi metode (fungsi) ingkang prasaja ing basa Jawi lumantar argumentasi. Watesan iki meksa pangembang Java 8 nambahake fitur kayata ekspresi Lambda menyang spesifikasi basa.

Napa Jawa mbutuhake ekspresi Lambda?

Wiwit wiwitan, basa Jawa ora akeh ngrembaka, kajaba mung Anotasi, Generik, lan liya-liyane. Sawise nggarap basa fungsional kayata JavaScript, siji bisa ngerti carane Jawa pancen orientasi obyek lan diketik banget. Fungsi ora dibutuhake ing Jawa. Dhewe, ora bisa ditemokake ing jagad Jawa. Ing basa pemrograman fungsional, fungsi dadi luwih penting. Dheweke ana dhewe. Sampeyan bisa nemtokake menyang variabel lan ngliwati argumen menyang fungsi liyane. JavaScript minangka salah sawijining conto paling apik saka basa pemrograman fungsional. Sampeyan bisa nemokake artikel apik ing Internet sing rinci babagan keuntungan JavaScript minangka basa fungsional. Basa fungsional duwe alat sing kuat kayata Closure, sing menehi sawetara kaluwihan tinimbang cara nulis aplikasi tradisional. Penutupan minangka fungsi kanthi lingkungan sing dilampirake - tabel sing nyimpen referensi kanggo kabeh variabel non-lokal saka fungsi kasebut. Ing Jawa, penutupan bisa disimulasikan liwat ekspresi Lambda. Mesthi, ana beda antarane penutupan lan ekspresi Lambda, lan ora cilik, nanging ekspresi lambda minangka alternatif sing apik kanggo penutupan. Ing blog sarkastik lan lucu, Steve Yegge nerangake carane donya Jawa wis strictly disambungake kanggo nouns (entitas, obyek - approx. transl. ). Yen sampeyan durung maca bloge, aku nyaranake. Dheweke nerangake kanthi cara sing lucu lan menarik babagan alesan kenapa ekspresi Lambda ditambahake ing Jawa. Ekspresi Lambda nggawa fungsionalitas menyang Jawa sing wis suwe ilang. Ekspresi Lambda nggawa fungsi kanggo basa kaya obyek. Sanajan iki ora 100% bener, sampeyan bisa ndeleng manawa ekspresi Lambda, sanajan ora ditutup, nyedhiyakake kemampuan sing padha. Ing basa fungsional, ekspresi lambda minangka fungsi; nanging ing Jawa, ekspresi lambda diwakili dening obyek, lan kudu digandhengake karo jinis obyek tartamtu sing diarani antarmuka fungsional. Sabanjure kita bakal ndeleng apa iku. Artikel Mario Fusco "Napa kita butuh Ekspresi Lambda ing Jawa" nerangake kanthi rinci kenapa kabeh basa modern mbutuhake kemampuan nutup.

Pambuka kanggo Lambda Expressions

Ekspresi Lambda minangka fungsi anonim (bisa uga ora 100% definisi sing bener kanggo Jawa, nanging ndadekake kajelasan). Cukup, iki minangka cara tanpa deklarasi, i.e. tanpa akses modifiers, bali Nilai lan jeneng. Ing cendhak, padha ngijini sampeyan kanggo nulis cara lan nggunakake langsung. Iku utamané migunani ing cilik saka telpon cara siji-wektu, amarga nyuda wektu kanggo wara-wara lan nulis cara tanpa kudu nggawe kelas. Ekspresi Lambda ing Jawa biasane duwe sintaks ing ngisor iki (аргументы) -> (тело). Tuladhane:
(арг1, арг2...) -> { тело }

(тип1 арг1, тип2 арг2...) -> { тело }
Ing ngisor iki sawetara conto ekspresi Lambda sing nyata:
(int a, int b) -> {  return a + b; }

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

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

() -> 42

() -> { return 3.1415 };

Struktur Ekspresi Lambda

Ayo sinau struktur ekspresi lambda:
  • Ekspresi Lambda bisa duwe 0 utawa luwih parameter input.
  • Jinis paramèter bisa ditemtokake kanthi eksplisit utawa bisa dipikolehi saka konteks. Tuladhane ( int a) bisa ditulis kaya mangkene ( a)
  • Parameter diapit ing kurung lan dipisahake karo koma. Contone ( a, b) utawa ( int a, int b) utawa ( String a, int b, float c)
  • Yen ora ana parameter, sampeyan kudu nggunakake tanda kurung kosong. Tuladhane() -> 42
  • Yen mung ana siji parameter, yen jinis ora ditemtokake kanthi jelas, kurung bisa diilangi. Tuladha:a -> return a*a
  • Awak ekspresi Lambda bisa ngemot 0 utawa luwih ekspresi.
  • Yen awak kasusun saka statement siji, iku bisa uga ora terlampir ing kurung kriting, lan Nilai bali bisa ditemtokake tanpa tembung kunci return.
  • Yen ora, kurung kriting dibutuhake (blok kode) lan nilai bali kudu ditemtokake ing pungkasan nggunakake tembung kunci return(yen jinis bali bakal void).

Apa antarmuka fungsional

Ing Jawa, antarmuka Marker minangka antarmuka tanpa nyatakake metode utawa kolom. Ing tembung liya, antarmuka token minangka antarmuka kosong. Kajaba iku, Antarmuka Fungsional minangka antarmuka kanthi mung siji metode abstrak sing diumumake. java.lang.Runnableminangka conto antarmuka fungsional. Iku mung nyatakake siji cara void run(). Ana uga antarmuka ActionListener- uga fungsional. Sadurunge, kita kudu nggunakake kelas anonim kanggo nggawe obyek sing ngleksanakake antarmuka fungsional. Kanthi ekspresi Lambda, kabeh dadi luwih gampang. Saben ekspresi lambda bisa diikat kanthi implisit menyang sawetara antarmuka fungsional. Contone, sampeyan bisa nggawe referensi menyang Runnableantarmuka, kaya sing ditampilake ing conto ing ngisor iki:
Runnable r = () -> System.out.println("hello world");
Konversi iki mesthi ditindakake kanthi implisit nalika kita ora nemtokake antarmuka fungsional:
new Thread(
    () -> System.out.println("hello world")
).start();
Ing conto ing ndhuwur, kompiler kanthi otomatis nggawe ekspresi lambda minangka implementasi Runnableantarmuka saka konstruktor kelas Thread: public Thread(Runnable r) { }. Ing ngisor iki sawetara conto ekspresi lambda lan antarmuka fungsional sing cocog:
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 };
Anotasi @FunctionalInterfacesing ditambahake ing Jawa 8 miturut Spesifikasi Basa Jawa mriksa manawa antarmuka sing diumumake bisa digunakake. Kajaba iku, Java 8 kalebu sawetara antarmuka fungsional sing siap digunakake kanggo ekspresi Lambda. @FunctionalInterfacebakal uncalan kesalahan kompilasi yen antarmuka ngumumaké ora fungsi. Ing ngisor iki minangka conto kanggo nemtokake antarmuka fungsional:
@FunctionalInterface
public interface WorkerInterface {

    public void doSomeWork();

}
Minangka definisi kasebut, antarmuka fungsional mung bisa duwe siji cara abstrak. Yen sampeyan nyoba nambah cara abstrak liyane, sampeyan bakal entuk kesalahan kompilasi. Tuladha:
@FunctionalInterface
public interface WorkerInterface {

    public void doSomeWork();

    public void doSomeMoreWork();

}
Kesalahan
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") );
    }

}
Kesimpulan:
Worker вызван через анонимный класс
Worker вызван через Lambda
Ing kene kita wis nemtokake antarmuka fungsional dhewe lan nggunakake ekspresi lambda. Cara kasebut execute()bisa nampa ekspresi lambda minangka argumen.

Conto ekspresi Lambda

Cara paling apik kanggo mangerteni ekspresi Lambda yaiku ndeleng sawetara conto: A stream Threadbisa diwiwiti kanthi rong cara:
// 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();
Manajemen acara ing Jawa 8 uga bisa ditindakake liwat ekspresi Lambda. Ing ngisor iki ana rong cara kanggo nambah panangan acara ActionListenermenyang komponen 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!");
});
Conto prasaja kanggo nampilake kabeh unsur array sing diwenehake. Elinga yen ana luwih saka siji cara kanggo nggunakake ekspresi lambda. Ing ngisor iki kita nggawe ekspresi lambda kanthi cara biasa nggunakake sintaks panah, lan uga nggunakake operator titik dobel (::), sing ing Jawa 8 ngowahi cara biasa dadi ekspresi lambda:
// 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);
Ing conto ing ngisor iki, kita nggunakake antarmuka fungsional Predicatekanggo nggawe item tes lan print sing lulus tes kasebut. Kanthi cara iki sampeyan bisa nyelehake logika menyang ekspresi lambda lan nindakake samubarang adhedhasar.
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();
    }

}
Kesimpulan:
Выводит все числа: 1 2 3 4 5 6 7
Не выводит ни одного числа:
Вывод четных чисел: 2 4 6
Вывод нечетных чисел: 1 3 5 7
Вывод чисел больше 5: 6 7
Kanthi tinkering karo ekspresi Lambda, sampeyan bisa nampilake kothak saben unsur dhaptar. Elinga yen kita nggunakake cara stream()kanggo ngowahi dhaptar biasa dadi stream. Java 8 nyedhiyakake kelas apik tenan Stream( java.util.stream.Stream). Isine ton cara migunani sing bisa digunakake ekspresi lambda. We pass expression lambda x -> x*xkanggo cara map(), kang ditrapake kanggo kabeh unsur ing stream. Sawisé iku kita digunakake forEachkanggo print kabeh unsur dhaftar.
// 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);
Diwenehi dhaftar, sampeyan kudu print jumlah kothak kabeh unsur dhaftar. Ekspresi Lambda ngidini sampeyan entuk iki kanthi nulis mung siji baris kode. Tuladha iki nggunakake metode konvolusi (reduksi) reduce(). Kita nggunakake cara map()kanggo kothak saben unsur, lan banjur nggunakake cara reduce()kanggo ambruk kabeh unsur menyang nomer siji.
// 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);

Bedane antarane ekspresi Lambda lan kelas anonim

Bentenane utama yaiku panggunaan tembung kunci this. Kanggo kelas anonim, tembung kunci '' thisnuduhake obyek saka kelas anonim, nalika ing ekspresi lambda, ' this' nuduhake obyek saka kelas sing digunakake ekspresi lambda. Bedane liyane yaiku cara dikompilasi. Jawa nyusun ekspresi lambda lan ngowahi dadi privatemetode kelas. Iki nggunakake instruksi invokedynamic , dikenalaké ing Jawa 7 kanggo cara dinamis naleni. Tal Weiss njlèntrèhaké ing blogé carane Jawa nyusun ekspresi lambda dadi bytecode

Kesimpulan

Mark Reinhold (Ketua Arsitek Oracle) nyebutake ekspresi Lambda minangka owah-owahan paling signifikan ing model pemrograman sing wis tau kedadeyan - malah luwih penting tinimbang generik. Dheweke mesthi bener, amarga ... padha menehi programer Java kapabilitas basa program fungsional saben wong wis nunggu. Bebarengan karo inovasi kayata metode ekstensi Virtual, ekspresi Lambda ngidini sampeyan nulis kode kanthi kualitas dhuwur. Muga-muga artikel iki bisa nggatekake basa Jawa 8. Good luck :)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION