函數(shù)式接口
函數(shù)式接口在Java中是指:有且僅有一個(gè)抽象方法的接口纹笼。
當(dāng)然接口中可以包含其他的方法(默認(rèn),靜態(tài),私有)
函數(shù)式接口,即適用于函數(shù)式編程場(chǎng)景的接口苟跪。而Java中的函數(shù)式編程體現(xiàn)就是Lambda廷痘,所以函數(shù)式接口就是可 以適用于Lambda使用的接口。只有確保接口中有且僅有一個(gè)抽象方法件已,Java中的Lambda才能順利地進(jìn)行推導(dǎo)笋额。
備注:“語(yǔ)法糖”是指使用更加方便,但是原理不變的代碼語(yǔ)法篷扩。例如在遍歷集合時(shí)使用的for-each語(yǔ)法兄猩,其實(shí) 底層的實(shí)現(xiàn)原理仍然是迭代器,這便是“語(yǔ)法糖”鉴未。從應(yīng)用層面來(lái)講枢冤,Java中的Lambda可以被當(dāng)做是匿名內(nèi)部 類的“語(yǔ)法糖”,但是二者在原理上是不同的铜秆。
@FunctionalInterface注解
作用:可以檢測(cè)接口是否是一個(gè)函數(shù)式接口
是:編譯成功
否:編譯失敗(接口中沒(méi)有抽象方法抽象方法的個(gè)數(shù)多余1個(gè))
函數(shù)式接口的使用:一般可以作為方法的參數(shù)和返回值類型
定義一個(gè)方法,參數(shù)使用函數(shù)式接口MyFunctionalInterface
public static void show(MyFunctionalInterface myInter){
myInter.method();
}
public static void main(String[] args) {
//1.調(diào)用show方法,方法的參數(shù)是一個(gè)接口,所以可以傳遞接口的實(shí)現(xiàn)類對(duì)象
show(new MyFunctionalInterfaceImpl());
//2.調(diào)用show方法,方法的參數(shù)是一個(gè)接口,所以我們可以傳遞接口的匿名內(nèi)部類
show(new MyFunctionalInterface() {
@Override
public void method() {
System.out.println("使用匿名內(nèi)部類重寫(xiě)接口中的抽象方法");
}
});
//3.調(diào)用show方法,方法的參數(shù)是一個(gè)函數(shù)式接口,所以我們可以Lambda表達(dá)式
show(()->{
System.out.println("使用Lambda表達(dá)式重寫(xiě)接口中的抽象方法");
});
//簡(jiǎn)化Lambda表達(dá)式
show(()-> System.out.println("使用Lambda表達(dá)式重寫(xiě)接口中的抽象方法"));
}
函數(shù)式編程
Lambda的延遲執(zhí)行
有些場(chǎng)景的代碼執(zhí)行后淹真,結(jié)果不一定會(huì)被使用,從而造成性能浪費(fèi)连茧。而Lambda表達(dá)式是延遲執(zhí)行的核蘸,這正好可以 作為解決方案,提升性能梅屉。
例:
使用Lambda優(yōu)化日志案例
Lambda的特點(diǎn):延遲加載
Lambda的使用前提,必須存在函數(shù)式接口
public class Demo02Lambda {
//定義一個(gè)顯示日志的方法,方法的參數(shù)傳遞日志的等級(jí)和MessageBuilder接口
public static void showLog(int level, MessageBuilder mb){
//對(duì)日志的等級(jí)進(jìn)行判斷,如果是1級(jí),則調(diào)用MessageBuilder接口中的builderMessage方法
if(level==1){
System.out.println(mb.builderMessage());
}
}
public static void main(String[] args) {
//定義三個(gè)日志信息
String msg1 = "Hello";
String msg2 = "World";
String msg3 = "Java";
//調(diào)用showLog方法,參數(shù)MessageBuilder是一個(gè)函數(shù)式接口,所以可以傳遞Lambda表達(dá)式
showLog(1,()->{
System.out.println("不滿足條件不執(zhí)行");
//返回一個(gè)拼接好的字符串
return msg1+msg2+msg3;
});
}
}
使用Lambda表達(dá)式作為參數(shù)傳遞,僅僅是把參數(shù)傳遞到showLog方法中
只有滿足條件,日志的等級(jí)是1級(jí)
才會(huì)調(diào)用接口MessageBuilder中的方法builderMessage
才會(huì)進(jìn)行字符串的拼接
如果條件不滿足,日志的等級(jí)不是1級(jí)
那么MessageBuilder接口中的方法builderMessage也不會(huì)執(zhí)行
所以拼接字符串的代碼也不會(huì)執(zhí)行
所以不會(huì)存在性能的浪費(fèi)值纱。
使用Lambda作為參數(shù)和返回值
例如java.lang.Runnable接口就是一個(gè)函數(shù)式接口,
假設(shè)有一個(gè)startThread方法使用該接口作為參數(shù)坯汤,那么就可以使用Lambda進(jìn)行傳參虐唠。
這種情況其實(shí)和Thread類的構(gòu)造方法參數(shù)為Runnable沒(méi)有本質(zhì)區(qū)別。
//定義一個(gè)方法startThread,方法的參數(shù)使用函數(shù)式接口Runnable
public static void startThread(Runnable run){
//開(kāi)啟多線程
new Thread(run).start();
}
public static void main(String[] args) {
//調(diào)用startThread方法,方法的參數(shù)是一個(gè)接口,那么我們可以傳遞這個(gè)接口的匿名內(nèi)部類
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"-->"+"線程啟動(dòng)了");
}
});
//調(diào)用startThread方法,方法的參數(shù)是一個(gè)函數(shù)式接口,所以可以傳遞Lambda表達(dá)式
startThread(()->{
System.out.println(Thread.currentThread().getName()+"-->"+"線程啟動(dòng)了");
});
//優(yōu)化Lambda表達(dá)式
startThread(()->System.out.println(Thread.currentThread().getName()+"-->"+"線程啟動(dòng)了"));
}
如果一個(gè)方法的返回值類型是一個(gè)函數(shù)式接口惰聂,那么就可以直接返回一個(gè)Lambda表達(dá)式疆偿。
當(dāng)需要通過(guò)一個(gè)方法來(lái)獲取一個(gè)java.util.Comparator接口類型的對(duì)象作為排序器時(shí),就可以調(diào)該方法獲取。
//定義一個(gè)方法,方法的返回值類型使用函數(shù)式接口Comparator
public static Comparator<String> getComparator(){
//方法的返回值類型是一個(gè)接口,那么我們可以返回這個(gè)接口的匿名內(nèi)部類
return new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//按照字符串的降序排序
return o2.length()-o1.length();
}
};
//方法的返回值類型是一個(gè)函數(shù)式接口,所有我們可以返回一個(gè)Lambda表達(dá)式
return (String o1, String o2)->{
//按照字符串的降序排序
return o2.length()-o1.length();
};
//繼續(xù)優(yōu)化Lambda表達(dá)式
return (o1, o2)->o2.length()-o1.length();
}
public static void main(String[] args) {
//創(chuàng)建一個(gè)字符串?dāng)?shù)組
String[] arr = {"aaa","b","cccccc","dddddddddddd"};
//輸出排序前的數(shù)組
System.out.println(Arrays.toString(arr));//[aaa, b, cccccc, dddddddddddd]
//調(diào)用Arrays中的sort方法,對(duì)字符串?dāng)?shù)組進(jìn)行排序
Arrays.sort(arr,getComparator());
//輸出排序后的數(shù)組
System.out.println(Arrays.toString(arr));//[dddddddddddd, cccccc, aaa, b]
}