Artikel iki kanggo sapa?
Sampeyan bisa maca liyane ing tutorial Oracle iki lan ing papan liya. Iki diarani " target typing ". Sampeyan bisa menehi jeneng variabel apa wae sing dikarepake - sampeyan ora kudu nggunakake jeneng sing padha sing ditemtokake ing antarmuka. Yen ora ana paramèter, mung nuduhake kurung kosong. Yen mung ana siji parameter, mung nuduhake jeneng variabel tanpa tanda kurung. Saiki kita ngerti paramèter, wektune kanggo ngrembug awak ekspresi lambda. Ing njero kurung kriting, sampeyan nulis kode kaya cara biasa. Yen kode sampeyan kalebu siji baris, sampeyan bisa ngilangi kurungan kriting kabeh (padha karo pernyataan yen lan kanggo-loop). Yen lambda siji-line ngasilake soko, sampeyan ora kudu kalebu a
- Iku kanggo wong sing mikir wis ngerti Java Core, nanging ora ngerti babagan ekspresi lambda ing basa Jawa. Utawa mungkin dheweke wis krungu babagan ekspresi lambda, nanging rincian kurang
- Iku kanggo wong sing duwe pangerten tartamtu babagan ekspresi lambda, nanging isih wedi karo dheweke lan ora biasa nggunakake.
-
Sampeyan kudu ngerti pemrograman berorientasi objek (OOP), yaiku:
- kelas, obyek, lan prabédan ing antarane;
- antarmuka, carane padha beda-beda saka kelas, lan hubungan antarane antarmuka lan kelas;
- cara, carane nelpon, cara abstrak (yaiku cara tanpa implementasine), paramèter metode, argumen metode lan cara kanggo ngliwati;
- akses modifiers, cara statis / variabel, cara final / variabel;
- warisan kelas lan antarmuka, sawetara warisan antarmuka.
- Kawruh Basa Jawa: jinis generik (generik), kumpulan (dhaptar), utas.
Sajarah sethitik
Ekspresi Lambda teka ing Jawa saka pemrograman fungsional, lan saka matématika. Ing Amerika Serikat ing tengah abad kaping 20, Gréja Alonzo, sing seneng banget karo matématika lan kabeh jinis abstraksi, kerja ing Universitas Princeton. Gereja Alonzo sing nemokke kalkulus lambda, sing wiwitane minangka kumpulan ide abstrak sing ora ana hubungane karo pemrograman. Matématikawan kayata Alan Turing lan John von Neumann makarya ing Universitas Princeton ing wektu sing padha. Kabeh teka bebarengan: Gréja teka munggah karo kalkulus lambda. Turing ngembangake mesin komputasi abstrak, saiki dikenal minangka "mesin Turing". Lan von Neumann ngusulake arsitèktur komputer sing dadi basis komputer modern (saiki diarani "arsitektur von Neumann"). Nalika iku, Gereja Alonzo Ide-ide kasebut ora kondhang kaya karya kanca-kancane (kajaba ing bidang matematika murni). Nanging, sethitik mengko John McCarthy (uga lulusan Universitas Princeton lan, ing wektu crita kita, karyawan Institut Teknologi Massachusetts) dadi kasengsem ing gagasan Church. Ing taun 1958, dheweke nggawe basa pemrograman fungsional pisanan, LISP, adhedhasar gagasan kasebut. Lan 58 taun sabanjure, ide-ide pemrograman fungsional bocor menyang Jawa 8. Ora nganti 70 taun kepungkur ... Jujur, iki dudu sing paling dawa kanggo ngetrapake ide matematika ing praktik. pegawe Institut Teknologi Massachusetts) dadi kasengsem ing gagasan Gréja. Ing taun 1958, dheweke nggawe basa pemrograman fungsional pisanan, LISP, adhedhasar gagasan kasebut. Lan 58 taun sabanjure, ide-ide pemrograman fungsional bocor menyang Jawa 8. Ora nganti 70 taun kepungkur ... Jujur, iki dudu sing paling dawa kanggo ngetrapake ide matematika ing praktik. pegawe Institut Teknologi Massachusetts) dadi kasengsem ing gagasan Gréja. Ing taun 1958, dheweke nggawe basa pemrograman fungsional pisanan, LISP, adhedhasar gagasan kasebut. Lan 58 taun sabanjure, ide-ide pemrograman fungsional bocor menyang Jawa 8. Ora nganti 70 taun kepungkur ... Jujur, iki dudu sing paling dawa kanggo ngetrapake ide matematika ing praktik.Atine prakara
Ekspresi lambda minangka jinis fungsi. Sampeyan bisa dianggep minangka cara Jawa biasa nanging kanthi kemampuan khas kanggo diterusake menyang metode liya minangka argumen. Bener. Wis dadi bisa kanggo pass ora mung nomer, strings, lan kucing kanggo cara, nanging uga cara liyane! Kapan kita butuh iki? Iku bakal mbiyantu, contone, yen kita arep kanggo pass sawetara cara callback. Yaiku, yen kita butuh metode sing kita sebut duwe kemampuan kanggo nelpon sawetara metode liyane sing kita tindakake. Ing tembung liyane, supaya kita duwe kemampuan kanggo pass siji callback ing kahanan tartamtu lan callback beda ing liyane. Lan supaya cara kita sing nampa callbacks nelpon. Ngurutake minangka conto prasaja. Upaminipun kita nulis sawetara algoritma ngurutake pinter sing katon kaya iki:public void mySuperSort() {
// We do something here
if(compare(obj1, obj2) > 0)
// And then we do something here
}
Ing if
statement, kita nelpon compare()
cara, maringaken ing rong obyek kanggo dibandhingake, lan kita pengin ngerti kang obyek iki "luwih gedhe". Kita nganggep sing "luwih gedhe" sadurunge sing "kurang". Aku sijine "luwih gedhe" ing kuotasi, amarga kita nulis cara universal sing bakal ngerti carane ngurutake ora mung ing urutan munggah, nanging uga ing urutan mudhun (ing kasus iki, obyek "luwih gedhe" bakal bener dadi obyek "kurang" , lan kosok balene). Kanggo nyetel algoritma tartamtu kanggo urutan kita, kita butuh sawetara mekanisme kanggo ngliwati mySuperSort()
metode kasebut. Kanthi cara iki, kita bakal bisa "ngontrol" metode kasebut nalika diarani. Mesthi, kita bisa nulis rong cara kapisah - mySuperSortAscend()
lanmySuperSortDescend()
- kanggo ngurutake ing urutan munggah lan mudhun. Utawa kita bisa ngirim sawetara argumentasi menyang metode kasebut (contone, variabel boolean; yen bener, banjur urutake ing urutan munggah, lan yen salah, banjur ing urutan mudhun). Nanging apa yen kita pengin ngurutake sing rumit kayata dhaptar array senar? Kepiye mySuperSort()
cara kita ngerti carane ngurutake array senar kasebut? Miturut ukuran? Miturut dawa kumulatif kabeh tembung? Mbok miturut abjad adhedhasar senar pisanan ing array? Lan yen kita kudu ngurutake dhaptar array kanthi ukuran array ing sawetara kasus, lan kanthi dawa kumulatif kabeh tembung ing saben array ing kasus liyane? Aku ngarepake sampeyan wis krungu babagan komparator lan ing kasus iki, kita mung bakal menehi cara ngurutake obyek komparator sing nggambarake algoritma pangurutan sing dikarepake. Amarga standarsort()
cara dileksanakake adhedhasar prinsip padha mySuperSort()
, Aku bakal nggunakake sort()
ing conto sandi.
String[] array1 = {"Dota", "GTA5", "Halo"};
String[] array2 = {"I", "really", "love", "Java"};
String[] array3 = {"if", "then", "else"};
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[]> sortByCumulativeWordLength = 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);
asil:
Dota GTA5 Halo
if then else
I really love Java
Ing kene, larik diurutake miturut jumlah tembung ing saben larik. Larik kanthi tembung sing luwih sithik dianggep "kurang". Pramila ingkang rumiyin. Larik kanthi tembung liyane dianggep "luwih gedhe" lan diselehake ing pungkasan. Yen kita ngliwati komparator sing beda karo sort()
metode kasebut, kayata sortByCumulativeWordLength
, mula kita bakal entuk asil sing beda:
if then else
Dota GTA5 Halo
I really love Java
Saiki array diurutake miturut jumlah total huruf ing tembung array. Ing array pisanan, ana 10 huruf, ing kaloro - 12, lan katelu - 15. Yen kita mung duwe comparator siji, banjur kita ora kudu wara-wara variabel kapisah kanggo iku. Nanging, kita mung bisa nggawe kelas anonim ing wektu nelpon sort()
metode kasebut. Kaya iki:
String[] array1 = {"Dota", "GTA5", "Halo"};
String[] array2 = {"I", "really", "love", "Java"};
String[] array3 = {"if", "then", "else"};
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;
}
});
Kita bakal entuk asil sing padha kaya ing kasus sing sepisanan. Tugas 1. Tulis maneh conto iki supaya ngurutake larik ora ing urutan munggah saka jumlah tembung ing saben larik, nanging ing urutan mudhun. Kita wis ngerti kabeh iki. Kita ngerti carane ngirim obyek menyang metode. Gumantung apa sing kita butuhake saiki, kita bisa ngirim obyek sing beda menyang metode, sing banjur bakal nggunakake metode sing ditindakake. Iki dadi pitakonan: kenapa ing jagad iki kita butuh ekspresi lambda ing kene? Amarga ekspresi lambda minangka obyek sing nduweni persis siji metode. Kaya "obyek metode". Cara sing dikemas ing obyek. Iku mung duwe sintaks sing rada ora pati ngerti (nanging luwih akeh babagan mengko). Ayo deleng maneh kode iki:
arrays.sort(new Comparator<String[]>() {
@Override
public int compare(String[] o1, String[] o2) {
return o1.length - o2.length;
}
});
Ing kene kita njupuk dhaptar array lan nelpon sort()
cara, sing kita pass obyek komparator kanthi compare()
cara siji (jenenge ora masalah kanggo kita - sawise kabeh, iku mung cara obyek iki, supaya kita ora bisa salah). Cara iki duwe rong paramèter sing bakal digarap. Yen sampeyan lagi makarya ing IntelliJ IDEA, sampeyan bisa uga ndeleng tawaran kasebut kanthi signifikan ngembun kode kaya ing ngisor iki:
arrays.sort((o1, o2) -> o1.length - o2.length);
Iki nyuda enem baris kanggo siji singkat. 6 baris ditulis maneh dadi siji cekak. Ana sing ilang, nanging aku njamin ora ana sing penting. Kode iki bakal bisa digunakake kanthi cara sing padha karo kelas anonim. Tugas 2. Njupuk guess ing rewriting solusi kanggo Tugas 1 nggunakake expression lambda (paling paling, takon IntelliJ IDEA Ngonversi kelas anonim kanggo expression lambda).
Ayo dadi pirembagan bab antarmuka
Ing asas, antarmuka mung dhaptar cara abstrak. Nalika kita nggawe kelas sing nindakake sawetara antarmuka, kelas kita kudu ngleksanakake cara sing kalebu ing antarmuka (utawa kita kudu nggawe abstrak kelas). Ana antarmuka karo akeh cara beda (contone,List
), lan ana antarmuka karo mung siji cara (contone, Comparator
utawa Runnable
). Ana antarmuka sing ora duwe cara siji (sing diarani antarmuka panandha kayata Serializable
). Antarmuka sing mung nduweni siji cara uga diarani antarmuka fungsional . Ing Jawa 8, malah ditandhani karo anotasi khusus:@FunctionalInterface
. Antarmuka siji-cara iki sing cocog minangka jinis target kanggo ekspresi lambda. Kaya sing dakkandhakake ing ndhuwur, ekspresi lambda minangka cara sing dibungkus ing obyek. Lan nalika kita ngliwati obyek kasebut, kita ateges ngliwati metode siji iki. Pranyata kita ora peduli apa sing diarani metode kasebut. Siji-sijine perkara sing penting kanggo kita yaiku paramèter metode lan, mesthi, awak metode kasebut. Intine, ekspresi lambda minangka implementasi antarmuka fungsional. Ing ngendi wae kita ndeleng antarmuka kanthi cara siji, kelas anonim bisa ditulis maneh minangka lambda. Yen antarmuka duwe luwih utawa kurang saka siji cara, ekspresi lambda ora bisa digunakake lan kita bakal nggunakake kelas anonim utawa malah conto kelas biasa. Saiki iku wektu kanggo dig menyang lambdas dicokot. :)
Sintaksis
Sintaks umum kaya iki:(parameters) -> {method body}
Yaiku, kurung sing ngubengi paramèter metode, "panah" (kawangun kanthi tandha hubung lan luwih saka tandha), banjur awak metode ing kurung, kaya biasane. Parameter kasebut cocog karo sing ditemtokake ing metode antarmuka. Yen jinis variabel bisa ditemtokake kanthi jelas dening kompiler (ing kasus kita, ngerti yen kita nggarap array string, amarga obyek List
diketik nggunakake String[
]), mula sampeyan ora kudu nuduhake jinise.
Yen padha ambigu, banjur nuduhake jinis. IDEA bakal menehi werna abu-abu yen ora dibutuhake. |
return
pratelan. Nanging yen sampeyan nggunakake kurung kriting, sampeyan kudu kanthi tegas nyakup return
statement, kaya sing sampeyan tindakake ing cara biasa.
Tuladha
Tuladha 1.() -> {}
Conto paling prasaja. Lan sing paling ora ana gunane :), amarga ora nindakake apa-apa. Tuladha 2.
() -> ""
Conto liyane sing menarik. Ora njupuk apa-apa lan ngasilake string kosong ( return
diilangi, amarga ora perlu). Mangkene bab sing padha, nanging karo return
:
() -> {
return "";
}
Tuladha 3. "Halo, Donya!" nggunakake lambdas
() -> System.out.println("Hello, World!")
Butuh apa-apa lan bali apa-apa (kita ora bisa sijine return
sadurunge telpon kanggo System.out.println()
, amarga println()
jinis bali cara iku void
). Iku mung nuduhake salam. Iki becik kanggo implementasine saka Runnable
antarmuka. Conto ing ngisor iki luwih lengkap:
public class Main {
public static void main(String[] args) {
new Thread(() -> System.out.println("Hello, World!")).start();
}
}
Utawa kaya iki:
public class Main {
public static void main(String[] args) {
Thread t = new Thread(() -> System.out.println("Hello, World!"));
t.start();
}
}
Utawa kita bisa nyimpen ekspresi lambda minangka Runnable
obyek lan banjur ngirim menyang Thread
konstruktor:
public class Main {
public static void main(String[] args) {
Runnable runnable = () -> System.out.println("Hello, World!");
Thread t = new Thread(runnable);
t.start();
}
}
Ayo dideleng kanthi cetha nalika ekspresi lambda disimpen ing variabel. Antarmuka Runnable
ngandhani yen obyek kasebut kudu duwe public void run()
metode. Miturut antarmuka, run
cara kasebut ora njupuk paramèter. Lan ora ngasilake apa-apa, yaiku jinis bali yaiku void
. Mulane, kode iki bakal nggawe obyek kanthi cara sing ora njupuk utawa ngasilake apa-apa. Iki cocog banget karo metode Runnable
antarmuka run()
. Pramila kita bisa nyelehake ekspresi lambda iki ing Runnable
variabel. Tuladha 4.
() -> 42
Maneh, ora butuh apa-apa, nanging ngasilake nomer 42. Ekspresi lambda kasebut bisa dilebokake ing Callable
variabel, amarga antarmuka iki mung ana siji cara sing katon kaya iki:
V call(),
endi V
jinis bali (ing kasus kita, int
). Dadi, kita bisa nyimpen ekspresi lambda kaya ing ngisor iki:
Callable<Integer> c = () -> 42;
Conto 5. A expression lambda nglibatno sawetara baris
() -> {
String[] helloWorld = {"Hello", "World!"};
System.out.println(helloWorld[0]);
System.out.println(helloWorld[1]);
}
Maneh, iki ekspresi lambda tanpa paramèter lan void
jinis bali (amarga ora ana return
statement). Tuladha 6
x -> x
Kene kita njupuk x
variabel lan bali. Elinga yen mung ana siji parameter, sampeyan bisa ngilangi tanda kurung ing sakubenge. Mangkene bab sing padha, nanging nganggo kurung:
(x) -> x
Lan ing ngisor iki conto kanthi pernyataan bali sing eksplisit:
x -> {
return x;
}
Utawa kaya iki nganggo tanda kurung lan pernyataan bali:
(x) -> {
return x;
}
Utawa kanthi indikasi eksplisit saka jinis kasebut (lan kanthi kurung):
(int x) -> x
Tuladha 7
x -> ++x
Kita njupuk x
lan bali, nanging mung sawise nambah 1. Sampeyan bisa nulis ulang lambda kaya iki:
x -> x + 1
Ing kasus loro, kita ngilangi tanda kurung ing sakubenge parameter lan awak metode, bebarengan karo statement return
, amarga padha opsional. Versi karo kurung lan statement bali diwenehi ing Conto 6. Conto 8
(x, y) -> x % y
We njupuk x
lan y
lan bali seko divisi saka x
dening y
. Ing kurung watara paramèter dibutuhake kene. Padha opsional mung yen ana mung siji parameter. Punika kanthi indikasi eksplisit babagan jinis:
(double x, int y) -> x % y
Tuladha 9
(Cat cat, String name, int age) -> {
cat.setName(name);
cat.setAge(age);
}
Kita njupuk Cat
obyek, String
jeneng, lan umur int. Ing cara dhewe, kita nggunakake jeneng liwati lan umur kanggo nyetel variabel ing kucing. Amarga cat
obyek kita minangka jinis referensi, bakal diganti ing njaba ekspresi lambda (bakal entuk jeneng lan umur sing liwati). Mangkene versi sing rada rumit sing nggunakake lambda sing padha:
public class Main {
public static void main(String[] args) {
// Create a cat and display it to confirm that it is "empty"
Cat myCat = new Cat();
System.out.println(myCat);
// Create a lambda
Settable<Cat> s = (obj, name, age) -> {
obj.setName(name);
obj.setAge(age);
};
// Call a method to which we pass the cat and lambda
changeEntity(myCat, s);
// Display the cat on the screen and see that its state has changed (it has a name and age)
System.out.println(myCat);
}
private static <T extends HasNameAndAge> void changeEntity(T entity, Settable<T> s) {
s.set(entity, "Smokey", 3);
}
}
interface HasNameAndAge {
void setName(String name);
void setAge(int age);
}
interface Settable<C extends HasNameAndAge> {
void set(C entity, String name, int age);
}
class Cat implements HasNameAndAge {
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 +
'}';
}
}
asil:
Cat{name='null', age=0}
Cat{name='Smokey', age=3}
Kaya sing sampeyan ngerteni, Cat
obyek kasebut duwe siji negara, banjur negara kasebut diganti sawise nggunakake ekspresi lambda. Ekspresi Lambda digabungake kanthi sampurna karo generik. Lan yen kita kudu nggawe Dog
kelas sing uga ngleksanakake HasNameAndAge
, mula kita bisa nindakake operasi sing padha ing metode Dog
kasebut main()
tanpa ngganti ekspresi lambda. Tugas 3. Tulis antarmuka fungsional kanthi cara sing njupuk nomer lan ngasilake nilai boolean. Tulis implementasi antarmuka kasebut minangka ekspresi lambda sing ngasilake bener yen nomer liwati bisa dibagi 13. Tugas 4.Tulis antarmuka fungsional kanthi cara sing njupuk rong senar lan uga ngasilake senar. Tulis implementasi antarmuka kaya ekspresi lambda sing ngasilake string sing luwih dawa. Tugas 5. Tulis antarmuka fungsional kanthi cara sing njupuk telung nomer floating-point: a, b, lan c lan uga ngasilake nomer floating-point. Tulis implementasine antarmuka kaya ekspresi lambda sing ngasilake diskriminan. Yen sampeyan lali, sing D = b^2 — 4ac
. Tugas 6. Nggunakake antarmuka fungsi saka Tugas 5, nulis expression lambda sing ngasilake asil saka a * b^c
. Panjelasan babagan ekspresi lambda ing basa Jawa. Kanthi conto lan tugas. Bagean 2