JavaRush /Blog Java /Random-MS /Ungkapan Lambda dengan contoh

Ungkapan Lambda dengan contoh

Diterbitkan dalam kumpulan
Java pada mulanya adalah bahasa berorientasikan objek sepenuhnya. Dengan pengecualian jenis primitif, segala-galanya di Jawa adalah objek. Malah tatasusunan adalah objek. Contoh setiap kelas adalah objek. Tiada satu pun kemungkinan untuk mentakrifkan fungsi secara berasingan (di luar kelas - lebih kurang transl. ). Dan tidak ada cara untuk meluluskan kaedah sebagai hujah atau mengembalikan badan kaedah sebagai hasil kaedah lain. memang macam tu. Tetapi ini sebelum Java 8. Ungkapan Lambda dengan contoh - 1Sejak zaman Swing lama yang baik, adalah perlu untuk menulis kelas tanpa nama apabila perlu untuk menghantar beberapa fungsi kepada beberapa kaedah. Contohnya, beginilah rupa menambahkan pengendali acara:
someObject.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {

                //Event listener implementation goes here...

            }
        });
Di sini kami ingin menambah beberapa kod pada pendengar acara tetikus. Kami menentukan kelas tanpa nama MouseAdapterdan segera mencipta objek daripadanya. Dengan cara ini, kami telah menyerahkan fungsi tambahan ke dalam addMouseListener. Ringkasnya, tidak mudah untuk lulus kaedah mudah (fungsi) di Jawa melalui hujah. Had ini memaksa pembangun Java 8 untuk menambah ciri seperti ungkapan Lambda pada spesifikasi bahasa.

Mengapa Java memerlukan ungkapan Lambda?

Sejak awal lagi, bahasa Java tidak banyak berkembang, kecuali untuk perkara seperti Anotasi, Generik, dll. Pertama sekali, Java sentiasa kekal berorientasikan objek. Selepas bekerja dengan bahasa berfungsi seperti JavaScript, seseorang boleh memahami bagaimana Java berorientasikan objek dan ditaip dengan kuat. Fungsi tidak diperlukan dalam Java. Dengan sendirinya, mereka tidak boleh ditemui di dunia Jawa. Dalam bahasa pengaturcaraan berfungsi, fungsi muncul di hadapan. Mereka wujud sendiri. Anda boleh menetapkannya kepada pembolehubah dan menyampaikannya melalui argumen kepada fungsi lain. JavaScript ialah salah satu contoh terbaik bahasa pengaturcaraan berfungsi. Anda boleh menemui artikel bagus di Internet yang memperincikan faedah JavaScript sebagai bahasa berfungsi. Bahasa fungsional mempunyai alat yang berkuasa seperti Penutupan, yang memberikan beberapa kelebihan berbanding kaedah tradisional aplikasi penulisan. Penutupan ialah fungsi dengan persekitaran yang dilampirkan padanya - jadual yang menyimpan rujukan kepada semua pembolehubah bukan tempatan bagi fungsi tersebut. Di Java, penutupan boleh disimulasikan melalui ungkapan Lambda. Sudah tentu, terdapat perbezaan antara penutupan dan ungkapan Lambda, dan bukan yang kecil, tetapi ungkapan lambda ialah alternatif yang baik untuk penutupan. Dalam blognya yang sarkastik dan kelakar, Steve Yegge menerangkan bagaimana dunia Jawa terikat dengan kata nama (entiti, objek - lebih kurang transl. ). Jika anda belum membaca blog beliau, saya syorkan. Dia menerangkan dengan cara yang lucu dan menarik sebab tepat mengapa ungkapan Lambda ditambahkan pada Java. Ungkapan Lambda membawa fungsi ke Java yang telah hilang sejak sekian lama. Ungkapan Lambda membawa kefungsian kepada bahasa seperti objek. Walaupun ini tidak 100% benar, anda dapat melihat bahawa ungkapan Lambda, walaupun bukan penutup, memberikan keupayaan yang serupa. Dalam bahasa berfungsi, ungkapan lambda ialah fungsi; tetapi dalam Java, ungkapan lambda diwakili oleh objek, dan mesti dikaitkan dengan jenis objek tertentu yang dipanggil antara muka berfungsi. Seterusnya kita akan melihat apa itu. Artikel Mario Fusco "Mengapa kita memerlukan Ekspresi Lambda di Jawa" menerangkan secara terperinci mengapa semua bahasa moden memerlukan keupayaan penutupan.

Pengenalan kepada Lambda Expressions

Ungkapan Lambda ialah fungsi tanpa nama (mungkin bukan 100% takrifan yang betul untuk Java, tetapi ia membawa sedikit kejelasan). Ringkasnya, ini adalah kaedah tanpa pengisytiharan, i.e. tanpa pengubah akses, mengembalikan nilai dan nama. Ringkasnya, mereka membenarkan anda menulis kaedah dan menggunakannya dengan segera. Ia amat berguna dalam kes panggilan kaedah sekali, kerana mengurangkan masa yang diperlukan untuk mengisytiharkan dan menulis kaedah tanpa perlu mencipta kelas. Ungkapan Lambda dalam Java biasanya mempunyai sintaks berikut (аргументы) -> (тело). Sebagai contoh:
(арг1, арг2...) -> { тело }

(тип1 арг1, тип2 арг2...) -> { тело }
Berikut ialah beberapa contoh ungkapan Lambda sebenar:
(int a, int b) -> {  return a + b; }

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

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

() -> 42

() -> { return 3.1415 };

Struktur Ungkapan Lambda

Mari kita kaji struktur ungkapan lambda:
  • Ungkapan Lambda boleh mempunyai 0 atau lebih parameter input.
  • Jenis parameter boleh ditentukan secara eksplisit atau boleh diperoleh daripada konteks. Contohnya ( int a) boleh ditulis seperti ini ( a)
  • Parameter disertakan dalam kurungan dan dipisahkan dengan koma. Contohnya ( a, b) atau ( int a, int b) atau ( String a, int b, float c)
  • Jika tiada parameter, maka anda perlu menggunakan kurungan kosong. Sebagai contoh() -> 42
  • Apabila terdapat hanya satu parameter, jika jenis tidak dinyatakan secara eksplisit, kurungan boleh ditinggalkan. Contoh:a -> return a*a
  • Badan ungkapan Lambda boleh mengandungi 0 atau lebih ungkapan.
  • Jika badan terdiri daripada satu pernyataan, ia mungkin tidak disertakan dalam pendakap kerinting dan nilai pulangan boleh ditentukan tanpa kata kunci return.
  • Jika tidak, pendakap kerinting diperlukan (blok kod) dan nilai pulangan mesti dinyatakan pada penghujung menggunakan kata kunci return(jika tidak, jenis pulangan ialah void).

Apakah antara muka berfungsi

Di Java, antara muka Penanda ialah antara muka tanpa mengisytiharkan kaedah atau medan. Dalam erti kata lain, antara muka token ialah antara muka kosong. Begitu juga, Antara Muka Fungsian ialah antara muka dengan hanya satu kaedah abstrak yang diisytiharkan padanya. java.lang.Runnableialah contoh antara muka berfungsi. Ia hanya mengisytiharkan satu kaedah void run(). Terdapat juga antara muka ActionListener- juga berfungsi. Sebelum ini, kami terpaksa menggunakan kelas tanpa nama untuk mencipta objek yang melaksanakan antara muka berfungsi. Dengan ungkapan Lambda, semuanya menjadi lebih mudah. Setiap ungkapan lambda boleh terikat secara tersirat pada beberapa antara muka berfungsi. Sebagai contoh, anda boleh membuat rujukan kepada Runnableantara muka, seperti yang ditunjukkan dalam contoh berikut:
Runnable r = () -> System.out.println("hello world");
Penukaran jenis ini sentiasa dilakukan secara tersirat apabila kami tidak menentukan antara muka berfungsi:
new Thread(
    () -> System.out.println("hello world")
).start();
Dalam contoh di atas, pengkompil secara automatik mencipta ungkapan lambda sebagai pelaksanaan Runnableantara muka daripada pembina kelas Thread: public Thread(Runnable r) { }. Berikut ialah beberapa contoh ungkapan lambda dan antara muka berfungsi yang sepadan:
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 @FunctionalInterfaceyang ditambahkan dalam Java 8 mengikut Spesifikasi Bahasa Java menyemak sama ada antara muka yang diisytiharkan berfungsi. Di samping itu, Java 8 termasuk beberapa antara muka berfungsi sedia untuk digunakan dengan ungkapan Lambda. @FunctionalInterfaceakan membuang ralat kompilasi jika antara muka yang diisytiharkan tidak berfungsi. Berikut ialah contoh mentakrifkan antara muka berfungsi:
@FunctionalInterface
public interface WorkerInterface {

    public void doSomeWork();

}
Seperti yang dicadangkan oleh definisi, antara muka berfungsi hanya boleh mempunyai satu kaedah abstrak. Jika anda cuba menambah kaedah abstrak lain, anda akan mendapat ralat penyusunan. Contoh:
@FunctionalInterface
public interface WorkerInterface {

    public void doSomeWork();

    public void doSomeMoreWork();

}
ralat
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
Di sini kami telah menentukan antara muka fungsi kami sendiri dan menggunakan ungkapan lambda. Kaedah ini execute()mampu menerima ungkapan lambda sebagai hujah.

Contoh ungkapan Lambda

Cara terbaik untuk memahami ungkapan Lambda adalah dengan melihat beberapa contoh: Strim Threadboleh dimulakan dalam dua 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();
Pengurusan acara dalam Java 8 juga boleh dilakukan melalui ungkapan Lambda. Berikut ialah dua cara untuk menambah pengendali acara ActionListenerpada 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!");
});
Contoh mudah untuk memaparkan semua elemen tatasusunan yang diberikan. Ambil perhatian bahawa terdapat lebih daripada satu cara untuk menggunakan ungkapan lambda. Di bawah ini kami mencipta ungkapan lambda dengan cara biasa menggunakan sintaks anak panah, dan kami juga menggunakan operator bertitik dua (::), yang dalam Java 8 menukar kaedah biasa kepada ungkapan 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);
Dalam contoh berikut, kami menggunakan antara muka berfungsi Predicateuntuk membuat ujian dan mencetak item yang lulus ujian tersebut. Dengan cara ini anda boleh meletakkan logik ke dalam ungkapan lambda dan melakukan perkara berdasarkannya.
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
Dengan bermain-main dengan ungkapan Lambda, anda boleh memaparkan segi empat sama setiap elemen senarai. Perhatikan bahawa kami menggunakan kaedah stream()untuk menukar senarai biasa kepada aliran. Java 8 menyediakan kelas yang hebat Stream( java.util.stream.Stream). Ia mengandungi banyak kaedah berguna yang anda boleh gunakan ungkapan lambda. Kami menghantar ungkapan lambda x -> x*xkepada kaedah map(), yang menggunakannya pada semua elemen dalam strim. Selepas itu kami gunakan forEachuntuk mencetak semua elemen senarai.
// 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);
Diberi senarai, anda perlu mencetak jumlah kuasa dua semua elemen senarai. Ungkapan Lambda membolehkan anda mencapai ini dengan menulis hanya satu baris kod. Contoh ini menggunakan kaedah lilitan (pengurangan) reduce(). Kami menggunakan kaedah map()untuk mengduakan setiap elemen, dan kemudian menggunakan kaedah reduce()untuk meruntuhkan semua elemen menjadi satu nombor.
// 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);

Perbezaan antara ungkapan Lambda dan kelas tanpa nama

Perbezaan utama ialah penggunaan kata kunci this. Untuk kelas tanpa nama, kata kunci ' ' thismenandakan objek kelas tanpa nama, manakala dalam ungkapan lambda, ' this' menandakan objek kelas di mana ungkapan lambda digunakan. Perbezaan lain ialah cara ia disusun. Java menyusun ungkapan lambda dan menukarnya kepada privatekaedah kelas. Ini menggunakan arahan invokedynamic , yang diperkenalkan dalam Java 7 untuk pengikatan kaedah dinamik. Tal Weiss menerangkan dalam blognya bagaimana Java menyusun ungkapan lambda ke dalam bytecode

Kesimpulan

Mark Reinhold (Ketua Arkitek Oracle) menggelar ungkapan Lambda sebagai perubahan paling ketara dalam model pengaturcaraan yang pernah berlaku - malah lebih ketara daripada generik. Dia pasti betul, kerana... mereka memberikan pengaturcara Java keupayaan bahasa pengaturcaraan berfungsi yang semua orang telah tunggu. Bersama-sama dengan inovasi seperti kaedah sambungan Maya, ungkapan Lambda membolehkan anda menulis kod yang sangat berkualiti tinggi. Saya harap artikel ini memberi anda pandangan di bawah tudung Java 8. Semoga berjaya :)
Komen
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION