Deskripsi sintaksis
Ekspresi lambda terdiri dari bagian -bagian berikut:
1. Daftar parameter formal yang dipisahkan secara koma dalam tanda kurung. Metode Checkperson.Test berisi parameter P, yang mewakili instance dari kelas orang. Catatan: Jenis parameter dalam ekspresi Lambda dapat dihilangkan; Selain itu, jika hanya ada satu parameter, tanda kurung juga dapat dihilangkan. Misalnya, kode yang disebutkan di bagian sebelumnya:
p -> p.getgender () == person.sex.male && p.getage ()> = 18 && p.getage () <= 25
2. Simbol panah: ->. Digunakan untuk memisahkan parameter dan tubuh fungsi.
3. Tubuh fungsi. Terdiri dari ekspresi atau blok kode. Dalam contoh di bagian sebelumnya, ungkapan ini digunakan:
p.getgender () == person.sex.male && p.getage ()> = 18 && p.getage () <= 25
Jika Anda menggunakan ekspresi, runtime Java akan menghitung dan mengembalikan nilai ekspresi. Selain itu, Anda juga dapat memilih untuk menggunakan pernyataan pengembalian di blok kode:
p -> {return p.getgender () == person.sex.male && p.getage ()> = 18 && p.getage () <= 25; }Namun, pernyataan pengembalian bukanlah ekspresi. Dalam ekspresi Lambda, pernyataan itu perlu dilampirkan dalam kawat gigi keriting, tetapi tidak perlu melampirkan pernyataan dalam kawat gigi keriting ketika hanya memanggil metode dengan nilai pengembalian kosong, sehingga metode penulisan berikut juga benar:
Email -> System.out.println (email)
Ada banyak kesamaan dalam deklarasi ekspresi dan metode Lambda. Oleh karena itu, ekspresi lambda juga dapat dianggap sebagai metode anonim, yaitu metode tanpa definisi nama.
Ekspresi lambda yang disebutkan di atas adalah semua ekspresi yang hanya menggunakan satu parameter sebagai parameter formal. Kelas contoh berikut, Caulator, menunjukkan cara menggunakan beberapa parameter sebagai parameter formal:
paket com.zhyea.zyTools; kalkulator kelas publik {antarmuka integermath {int operasi (int a, int b); } public int operationBinary (int a, int b, integermath op) {return op.Operation (a, b); } public static void main (string ... args) {calculator myapp = new calculator (); Integermath penambahan = (a, b) -> a + b; System.out.println ("40 + 2 =" + myApp.OperaterBinary (40, 2, penambahan)); System.out.println ("20 - 10 =" + myApp.OperaterBinary (20, 10, pengurangan)); }}Metode OperatingBinary dalam kode menggunakan dua parameter integer untuk melakukan operasi aritmatika. Operasi aritmatika di sini sendiri merupakan contoh dari antarmuka integermath. Dalam program di atas, dua operasi aritmatika didefinisikan menggunakan ekspresi Lambda: penambahan dan pengurangan. Mengeksekusi program akan mencetak konten berikut:
40 + 2 = 4220 - 10 = 10
Mengakses variabel lokal dari kelas eksternal
Mirip dengan kelas lokal atau kelas anonim, ekspresi Lambda juga dapat mengakses variabel lokal kelas eksternal. Perbedaannya adalah bahwa tidak perlu mempertimbangkan masalah seperti mengesampingkan saat menggunakan ekspresi lambda. Ekspresi Lambda hanyalah konsep leksikal, yang berarti tidak perlu mewarisi nama apa pun dari superclass, juga tidak memperkenalkan lingkup baru. Artinya, deklarasi dalam ekspresi lambda memiliki arti yang sama dengan deklarasi di lingkungan eksternalnya. Ini ditunjukkan dalam contoh berikut:
Paket com.zhyea.zytools; import java.util.function.consumer; kelas publik lambdascopetest {public int x = 0; kelas firstlevel {public int x = 1; void methodInfirstlevel (int x) {// Pernyataan berikut akan menyebabkan kompiler melaporkan kesalahan "variabel lokal yang dirujuk dari ekspresi lambda harus final atau final secara efektif" // x = 99; Konsumen <integer> myconsumer = (y) -> {System.out.println ("x =" + x); // pernyataan a system.out.println ("y =" + y); System.out.println ("this.x =" + this.x); System.out.println ("lambdascopetest.this.x =" + lambdascopetest.this.x); }; myconsumer.accept (x); }} public static void main (string ... args) {lambdascopetest st = new lambdascopetest (); Lambdascopetest.firstlevel fl = st.new firstlevel (); fl.methodinfirstlevel (23); }}Kode ini akan menghasilkan yang berikut:
x = 23y = 23this.x = 1lambdascopetest.pis.x = 0
Jika Anda mengganti parameter y dalam mikonsumer ekspresi lambda dalam contoh dengan x, kompiler akan melaporkan kesalahan:
Konsumen <Integer> myconsumer = (x) -> {// ....};Pesan kesalahan kompiler adalah: "Variabel x sudah didefinisikan dalam metode metodeinfirstlevel (int)", yang berarti bahwa variabel x telah didefinisikan dalam metode metodeinfirstlevel. Kesalahan dilaporkan karena ekspresi lambda tidak memperkenalkan ruang lingkup baru. Oleh karena itu, Anda dapat secara langsung mengakses bidang domain, metode dan parameter formal dari kelas eksternal dalam ekspresi lambda. Dalam contoh ini, mikonsumer ekspresi lambda secara langsung mengakses parameter x metode metodeinfirstlevel. Saat mengakses anggota kelas eksternal, kata kunci ini juga digunakan secara langsung. Dalam contoh ini this.x mengacu pada firstlevel.x.
Namun, seperti kelas lokal atau anonim, ekspresi Lambda hanya dapat mengakses variabel lokal atau anggota eksternal yang dinyatakan sebagai final (atau setara dengan final). Misalnya, kami menghapus komentar sebelum "x = 99" dalam metode Contoh Kode MetodePirstLevel:
// Pernyataan berikut akan menyebabkan kompiler melaporkan kesalahan "variabel lokal yang dirujuk dari ekspresi lambda harus final atau final secara efektif" x = 99; Konsumen <integer> myconsumer = (y) -> {System.out.println ("x =" + x); // pernyataan a system.out.println ("y =" + y); System.out.println ("this.x =" + this.x); System.out.println ("lambdascopetest.this.x =" + lambdascopetest.this.x); };Karena nilai parameter x dimodifikasi dalam pernyataan ini, parameter x MethodInfirstlevel tidak lagi dapat dianggap final. Oleh karena itu, kompiler Java akan melaporkan kesalahan seperti "variabel lokal yang dirujuk dari ekspresi lambda harus final atau final secara efektif" di mana ekspresi Lambda mengakses variabel lokal x.
Tipe target
Bagaimana cara menentukan jenis ekspresi lambda? Mari kita lihat kode untuk menyaring personel militer dengan usia yang sesuai:
p -> p.getgender () == person.sex.male && p.getage ()> = 18 && p.getage () <= 25
Kode ini telah digunakan di dua tempat:
Public Static Void Printpersons (Daftar <son> Roster, Checkperson Tester) - Solusi 3
public void printpersonsWithPredicate (daftar <sen person>, predikat <son> tester) - Plan VI
Saat memanggil metode printpersons, metode ini mengharapkan parameter tipe checkperson. Pada saat ini, ekspresi di atas adalah ekspresi tipe pemeriksa. Saat memanggil Metode PrintpersonswithPredicate, parameter tipe predikat <FERON> diharapkan. Pada saat ini, ungkapan yang sama adalah tipe predikat <son>. Seperti ini, jenis yang ditentukan oleh jenis yang diharapkan dengan metode ini disebut tipe target (sebenarnya, saya pikir jenis inferensi di Scala lebih tepat di sini). Kompiler Java menentukan jenis ekspresi lambda melalui konteks tipe target atau posisi saat menemukan ekspresi lambda. Ini berarti bahwa ekspresi lambda hanya dapat digunakan di mana kompiler java dapat menyimpulkan jenis:
Jenis target dan parameter metode
Untuk parameter metode, kompiler Java juga perlu mengandalkan dua fitur bahasa untuk menentukan jenis target: parsing kelebihan beban dan inferensi parameter tipe.
Lihatlah dua antarmuka fungsional berikut (java.lang.runnable dan java.util.concurrent.callable <v>):
antarmuka publik runnable {void run (); } antarmuka publik Callable <V> {v call (); }Metode runnable.run () tidak mengembalikan nilai, sedangkan metode callable.call () memilikinya.
Misalkan kita membebani metode Invoke seperti yang berikut:
void Invoke (runnable r) {r.run (); } <T> t Invoke (Callable <T> C) {return c.call (); }Jadi metode mana yang akan dipanggil dalam pernyataan berikut:
String s = invoke(() -> "done");
Invoke (Callable <T>) dipanggil karena metode ini memiliki nilai pengembalian, saat Invoke (Runnable <T>) tidak mengembalikan nilai. Dalam hal ini jenis ekspresi lambda (() -> "selesai") adalah callable <T>.
Serialisasi
Jika jenis target dari ekspresi lambda dan jenis parameter yang disebutnya dapat di -serializable, maka ekspresi lambda juga dapat di -serial. Namun, seperti kelas dalam, serialisasi ekspresi Lambda sangat tidak dianjurkan.