1.lambda表達式基礎(chǔ)
?lambda表達式是一個可傳遞的代碼塊灭美,可以在以后執(zhí)行一次或多次。Java中常見的lambda表達式形式:(參數(shù))铁坎、箭頭(→)以及一個表達式犁苏。如果代碼要完成的計算無法放在一個表達式中,可以使用{ }朴乖。
(String first, String second) ->
{
if(first.length() < second.length) return -1;
else if (first.length() > second.length()) return 1;
else return 0;
}
?即使lambda表達式沒有參數(shù)助赞,仍然要提供空括號买羞,就像無參數(shù)方法一樣雹食。
() -> { for (int i = 100; i > = 0; i--) System.out.println(i);}
?如果可以推導(dǎo)出一個lambda表達式的參數(shù)類型,則可以忽略其類型吃挑。例如:
Comparator<String> comp = (first, second) -> first.length() - second.length();
?如果方法只有一個參數(shù)街立,而且這個參數(shù)的類型可以推導(dǎo)得出,還可以省略小括號:
ActionListener listener = event -> System.out.println("The time is");
?無需指定lambda表達式的返回類型逛犹。lambda表達式的返回類型總是會由上下文推導(dǎo)得出梁剔。
2.lambda表達式轉(zhuǎn)換成函數(shù)式接口
?對于只有一個抽象方法的接口,需要這種接口的對象時,就可以提供一個lambda表達式喷鸽。這種接口稱為函數(shù)式接口。
?為了展示如何轉(zhuǎn)換為函數(shù)式接口砾省,下面考慮Arrays.sort方法。它的第二個參數(shù)需要一個Comparator實例轩性,Comparator就是只有一個方法的接口狠鸳,所以可以提供一個lambda表達式件舵,最好把lambda表達式看作是一個函數(shù),而不是一個對象:
Arrays.sort(words, (first, second) -> first.length() - second.length());
?使用lambda表達式的重點是延遲執(zhí)行铅祸,需要清楚了解函數(shù)式接口的參數(shù)類型临梗、參數(shù)個數(shù)以及返回值類型,才能更好的使用lambda表達式盟庞。
?來看一個簡單的例子茫经。假設(shè)想要重復(fù)一個動作n次。將這個動作和重復(fù)次數(shù)傳遞到一個repeat方法:
repeat(10, ()-> System.out.println("Hello, World!"));
要接受這個lambda表達式抹镊,需要選擇一個函數(shù)式接口荤傲。這里提供Runnable接口:
public static void repeat(int n, Runnable action) {
for (int i = 0; i < n; i++) action.run;
}
當調(diào)用action.run()時會執(zhí)行這個lambda表達式的主體。
?下面給出JavaAPI中提供的最重要的函數(shù)式接口:?有時可能需要自己設(shè)計接口终佛,若其中只有一個抽象方法雾家,可以用@FunctionalInterdace注釋來標記這個接口芯咧。在javadoc頁里會指出你的接口是一個函數(shù)式接口竹揍。
3.lambda表達式實現(xiàn)方法引用
?有時邪铲,可能已經(jīng)有現(xiàn)成的方法可以完成你想要傳遞到其他代碼的某個動作,可以對已有的方法進行引用。
?主要有3種情況:
- object::instanceMethod 對象的實例方法
- Class::staticMethod 類的靜態(tài)方法
-
Class::instanceMethod 類的實例方法
?例:
//正常寫法昧碉,匿名類
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
v.getId();
}
});
//lambda表達式
mButton.setOnClickListener(v-> v.getId());
//類的實例方法引用 --- (view, args)->view.getId(args)
mButton.setOnClickListener(View::getId);
//對象的實例方法引用 --- (view)->viewGroup.addView(view)
mButton.setOnClickListener(viewGroup::addView);
//類的靜態(tài)方法引用 --- (view)-> MyTest.getId(view);
mButton.setOnClickListener(MyTest::getId);
public class MyTest {
public static void getId(View view) {}
}
?對于Class::instanceMethod被饿,第一個參數(shù)會成為方法的隱式參數(shù)永丝,第二個參數(shù)(假如有)會成為顯式參數(shù)。
?對于object::instanceMethod和Class::staticMethod哥牍,方法引用等價于提供方法參數(shù)的lambda表達式喝检。即lambda表達式的參數(shù)成為所引用方法的顯示參數(shù)。
?特別注意:可以在方法引用中使用this和super參數(shù)澡谭。
this::equals 等同于 x-> this.equals(x)
super::instanceMethod 會調(diào)用給定方法的超類版本
4.構(gòu)造器引用
?構(gòu)造器引用與方法引用類似损俭,只不過方法名為new杆兵。
Person::new是Person構(gòu)造器的一個引用,具體調(diào)用哪個構(gòu)造器攒砖,取決于上下文
int[ ]::new是一個構(gòu)造器引用日裙,它有一個參數(shù):即數(shù)組的長度。等價于 x->new int[x]
5.lambda表達式中變量的作用域
?通常昂拂,我們希望能夠在lambda表達式中訪問外圍方法或類中的變量。
public static void repeatMessage(String text, int delay) {
ActionListener listener = event -> {
System.out.println(text);
Toolkit.getDefaultTookit().beep();
};
new Timer(delay, listener).start();
}
?lambda表達式中的變量text路克,并不是在這個lambda表達式中定義的精算。lambda表達式可能會在repeatMessage調(diào)用返回很久后才開始運行碎连,而那時候text這個變量參數(shù)可能已經(jīng)不存在了。
?實際上廉嚼,lambda表達式由3部分組成:
- 一個代碼塊
- 參數(shù)
-
自由變量的值倒戏,指非參數(shù)而且不再代碼中定義的變量。
?可以看到傍念,lambda表達式可以捕獲外圍作用域中變量的值葛闷。lambda表達式中捕獲的變量必須是最終變量,即這個變量初始化后就不會再改變淑趾。
?在一個lambda表達式中使用this關(guān)鍵字阳仔,是指創(chuàng)建這個lambda表達式的方法的this參數(shù)。
public class Application() {
public void init() {
ActionListener listener = event -> {
System.out.println(this.toString());
}
}
}
?表達式this.toString()會調(diào)用Application對象的toString方法扣泊,而不是ActionListener實例的方法近范。