0x00 JS中的閉包以及Java中替代方法
在Java中,是不允許將一個(gè)方法作為參數(shù)傳遞給另一個(gè)函數(shù),也不允許將一個(gè)方法作為值盅视,返回給調(diào)用者捐名,這就是所謂的不支持閉包。
但是JavaScript是可以這么玩的闹击。比如:
getWebResource(function(result,error){
if(error){
doException();
}else{
analysisResult(result);
}
});
我們看到直接向getWebResource
方法中傳遞了一個(gè)function
镶蹋,這個(gè)function用來解析網(wǎng)絡(luò)請求結(jié)果。
但是Java不能這樣赏半,那Java一般是怎么玩耍的呢贺归?
我們來看一段Android內(nèi)的Java代碼
loginBtn = (Button) findViewById(R.id.btn_login);
loginBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Login();
}
});
很明顯,我們?yōu)?code>loginBtn設(shè)置了一個(gè)點(diǎn)擊監(jiān)聽回調(diào)函數(shù)除破,這函數(shù)中牧氮,傳遞了View.OnClickListener
的匿名實(shí)例對象琼腔,我們通過實(shí)例對象瑰枫,調(diào)用onClick(View view)
方法。
這樣丹莲,通過匿名對象光坝,我們可以實(shí)現(xiàn)類似js中的閉包的功能,不過我們是通過匿名對象調(diào)用函數(shù)甥材,而不是直接調(diào)用函數(shù)盯另,還是有區(qū)別的
0x01 函數(shù)式接口
上面,我們看到View
類中的OnClickListener
接口洲赵。這個(gè)接口負(fù)責(zé)接收點(diǎn)擊事件的回調(diào)
public interface OnClickListener {
void onClick(View var1);
}
這個(gè)接口有且僅有一個(gè)抽象方法鸳惯,這種接口,我們稱為函數(shù)式接口(FunctionalInterface
)叠萍。這是Java8中添加的新的支持芝发。
可以看看Java8的API
java.lang.FunctionalInterface
API:https://docs.oracle.com/javase/8/docs/api/java/lang/FunctionalInterface.html
這是個(gè)標(biāo)注函數(shù)式接口的注解。里面的注釋苛谷,解釋了函數(shù)式接口辅鲸,和這個(gè)注解的用法。
就不翻譯了腹殿,大致意思是:
- 函數(shù)式接口就是:一個(gè)interface独悴,里面只有一個(gè)抽象方法,其他什么都沒有锣尉。
- FunctionalInterface注解標(biāo)注一個(gè)函數(shù)式接口刻炒,不能標(biāo)注
類
,方法
自沧,枚舉
坟奥,屬性
這些。 - 如果接口被標(biāo)注了
@FunctionalInterface
窖张,這個(gè)類就必須符合函數(shù)式接口的規(guī)范 - 即使一個(gè)接口沒有標(biāo)注
@FunctionalInterface
脊奋,如果這個(gè)接口滿足函數(shù)式接口規(guī)則,依舊被當(dāng)作函數(shù)式接口败潦。
注意:interface中重寫Object類中的抽象方法管行,不會(huì)增加接口的方法數(shù)厨埋,因?yàn)榻涌诘膶?shí)現(xiàn)類都是Object的子類。接口中的默認(rèn)方法(
default
修飾的方法)也不算捐顷。
說完這些荡陷,我們該說一下神奇的Lambda表達(dá)式了
0x02 Lambda表達(dá)式
“Lambda 表達(dá)式”(Lambda expression)是一個(gè)匿名函數(shù),Lambda表達(dá)式基于數(shù)學(xué)中的λ演算得名迅涮,直接對應(yīng)于其中的Lambda抽象(Lambda abstraction)废赞,是一個(gè)匿名函數(shù),即沒有函數(shù)名的函數(shù)叮姑。Lambda表達(dá)式可以表示閉包(注意和數(shù)學(xué)傳統(tǒng)意義上的不同)唉地。
——百度百科
Java中的Lambda表達(dá)式有三種形式,我們來舉3個(gè)例子
//1.
() -> System.out.println("Hello Lambda");
//2.
(number1, number2) -> int a = number1 + number2;
//3.
(number1, number2) -> {
int a = number1 + number2;
System.out.println(a);
}
大致形式就是
(param1, param2, param3, param4…)->{ doing……}传透;
就是一個(gè)匿名的函數(shù)式接口的縮寫耘沼。
很明顯,在之前的代碼中朱盐,我們用到了匿名對象群嗤,這個(gè)匿名對象就是一個(gè)函數(shù)式接口的子對象,所以兵琳,在Java8中可以使用Lambda表達(dá)式
我們把剛剛的代碼簡化成Lambda表達(dá)
loginBtn = (Button) findViewById(R.id.btn_login);
loginBtn.setOnClickListener((view)-> Login());
瞬間簡潔了狂秘,有木有?
然后呢躯肌?因?yàn)橛辛撕瘮?shù)式接口的標(biāo)準(zhǔn)者春,Java8中的List,有了一個(gè)新方法羡榴,叫forEach碧查,下面演示一下這個(gè)方法。
package com.zing.lambda_demo;
import java.util.Arrays;
import java.util.List;
/**
* Created by zing on 2016/12/21.
*/
public class FunctionalInterfaceTest {
public static void main(String[] args) {
List<Integer> demoList = Arrays.asList(1, 2, 3, 4, 5);
demoList.forEach((num) -> System.out.println(num));
}
}
當(dāng)然校仑,Lambda表達(dá)式雖然簡潔忠售,也是有缺點(diǎn)的:就是降低了代碼的可讀性,比如一眼看不出來原來的函數(shù)式接口是什么迄沫。
所以什么情況用Lambda稻扬,要多寫多練才會(huì)用的恰當(dāng)。
ps:我就不解釋forEach具體方法了羊瘩,貼倆圖你看看實(shí)現(xiàn)和注解
謝謝收看泰佳,我的博客:http://www.azing.xyz 歡迎光顧盼砍。
love&peace
FS全棧計(jì)劃目錄:https://micorochio.github.io/fs-plan/