又是熱愛學習的一天!!!
語法簡介
Java8引入了一種新的操作符 “->”,該操作符叫做 箭頭操作符 或者叫做 Lambda 操作符。箭頭操作符將Lambda表達式分爲了左右兩部分
- 左側:Lambda 表達式的參數列表。
- 右側:Lambda 表達式所需執行的功能,也叫Lambda體。
上一篇 初識Lambda文章說道 ,Lambda表達式就是對接口的實現。以前是用匿名內部類去實現的接口,現在是用的Lambda表達式去實現的。
拿上篇文章的 StudentFilter 接口舉例,接口中有個 filter 抽象方法。那麼Lambda表達式的左側就代表的 filter 方法的參數列表。Lambda表達式的右側就是這個方法具體實現的功能
這裏有一個疑問:Lambda 表達式自動的就找到了StudentFilter 接口中的 filter 抽象方法,如果這個接口中有多個抽象方法呢?該怎麼辦?
這裏引出一個新概念:函數式接口
函數式接口
所謂函數式接口就是指接口中只有一個抽象方法的接口,我們稱爲函數式接口。
可以使用註解:@FunctionalInterface 來修飾
如果使用了該註解,那麼就可以檢測這個接口是不是函數式接口,不寫也可以,但是得人工保證函數式接口的規範。而 Lambda 表達式就必須依賴一個函數式接口!
因爲函數式接口的抽象方法可能是多種多樣,比如無參數無返回值、無參數有返回值、有參數無返回值和有參數有返回值等多種情況,那麼就有對應的幾種略微不同的寫法。
語法格式
語法格式一:無參數無返回值
我們在前面說到,Lambda表達式需要函數式接口的支持,那這裏我們是不是需要新創建一個接口,並且增加一個無參數無返回值的抽象方法呢?
其實不用,這種抽象方法其實在Java中已經有一個了,比如:Runnable 接口就是一個函數式接口,接口中的 run 方法就是 無參數無返回值的。
/**
* 語法格式一:無參數無返回值
* () -> System.out.println("Hello Lambda")
*/
@Test
public void grammar_1(){
// 原來匿名內部類的寫法
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello Inner class");
}
};
r.run();
System.out.println("************昏 哥 線*************");
// 現在使用 Lambda 表達式的寫法
Runnable runnable = () -> System.out.println("Hello Lambda");
runnable.run();
}
執行結果:
Hello Inner class
************昏 哥 線*************
Hello Lambda
這裏需要提一點: 在 jdk 1.7及以前 如果一個局部類 引用了一個局部變量,那麼這個變量 需要顯示的聲明成 final,在 1.8中就不用顯示的去聲明瞭,編譯器默認給我們加上了,但是這個變量任然是 final 的,是不可以修改的,使用如下所示:
@Test
public void grammar_1(){
int num = 25; // jdk 1.7及以前,需要顯示的聲明成 final
// 原來匿名內部類的寫法
Runnable r = new Runnable() {
@Override
public void run() {
System.out.println("Hello Inner class" + num);
}
};
r.run();
System.out.println("************昏 哥 線*************");
// 現在使用 Lambda 表達式的寫法
Runnable runnable = () -> System.out.println("Hello Lambda" + num);
runnable.run();
}
語法格式二:有一個參數 無返回值
有一個參數,無返回值的這個接口。 Java裏面也有現成的,他就是:Consumer 接口,它裏面的 accept 抽象方法就符合我們的要求:
/**
* 語法格式二:有一個參數 無返回值
* (x) -> System.out.println(x)
*
* 注意:如果只有一個參數,那麼 Lambda表達式左側小括號可以省略不寫,但是建議還是寫上。
*/
@Test
public void grammar_2(){
Consumer consumer = (x) -> System.out.println(x);
consumer.accept("你好,Lambda");
}
語法格式三:有兩個及以上參數 有返回值,並且 Lambda體中有多條語句
這種接口Java裏面也有!它就是:Comparator 接口,它裏面的 compare 方法就符合我們的要求:
/**
* 語法格式三:有兩個及以上參數 有返回值,並且 Lambda體中有多條語句,那麼 Lambda 體需要使用大括號括起來。
*
* 注意:如果兩個及以上參數 有返回值,但是 Lambda 體只有一條語句的話,那麼 return 和 大括號可以省略不寫。
*/
@Test
public void grammar_3(){
Comparator<Integer> comparator = (x, y) -> {
System.out.println("這是多條語句的 Lambda 體...");
return Integer.compare(x, y);
};
int result = comparator.compare(100, 200);
System.out.println("返回值爲:"+result);
System.out.println("************昏 哥 線*************");
// 這是 Lambda 體只有一條語句的話,那麼 return 和 大括號可以省略不寫 的情況。
Comparator<Integer> c = (x, y) -> Integer.compare(x, y);
int result2 = c.compare(200, 500);
System.out.println("返回值爲:"+result2);
}
回頭看幾個 Lambda 語句,會發現 小括號裏面的參數都是沒有數據類型的,但是編譯運行都沒有問題,這就說明了,Lambda表達式的參數列表的數據類型可以省略不寫,因爲 JVM 編譯器可以通過上下文推斷出數據類型,這個過程就叫做 類型推斷
番外
在上面說到函數式接口中只能有一個抽象方法,但是 Comparator 接口中除去 default 修飾的方法之外,還有兩個,分別是:compare 和 equals。那麼它爲啥還是屬於函數式接口呢?
原因就是 equals 它是 Object的方法,他已經有了默認實現,所以他不算是接口中的抽象方法
從 類的註釋來看,可以總結出以下三點:
- 一個函數式接口有且只有一個抽象方法。
- 默認方法不是抽象方法,因爲它們已經實現了。
- 重寫了超類Object類中任意一個public方法的方法並不算接口中的抽象方法。
所以說 Comparator 接口還是隻有 compare 這一個抽象方法,所以他符合函數式接口的標準
簡單示例
需求:對指定數字進行運算
先創建一個函數式接口
@FunctionalInterface
public interface ICalculation<T> {
int calc(T x, T y);
}
再寫一個操作方法 operation,具體進行什麼運算現在還不知道,我們對傳入的參數 x 和參數 y 進行運算並返回結果。
public int operation(int x, int y, ICalculation<Integer> iCalculation){
return iCalculation.calc(x, y);
}
調用 操作方法 operation,傳入實參,使用 Lambda 表達式實現接口中的抽象方法進行運算。下面演示了乘法、加法和減法運算。
@Test
public void lambdaGrammar(){
int operation = operation(10, 5, (x, y) -> x * y);
System.out.println("乘法運算結果:"+operation);
System.out.println("*******昏 哥 線************");
System.out.println("加法運算結果:"+operation(10, 5, (x, y) -> x + y));
System.out.println("*******昏 哥 線************");
System.out.println("減法運算結果:"+operation(10, 5, (x, y) -> x - y));
}
運行結果:
乘法運算結果:50
*******昏 哥 線************
加法運算結果:15
*******昏 哥 線************
減法運算結果:5
總結
Lambda 表達式的語法其實比較簡單,重點是分清它左右側分別是什麼內容,它的左側就對應着函數式接口中抽象方法的參數列表,在它的左側是可以不用寫數據類型的,是因爲有類型推斷機制。如果非要寫上數據類型,那就必須將所有參數都加上數據類型纔可以。
它的右側就是 Lambda 體,就是我們具體實現的內容,如果有多條語句需要使用大括號,只有一條語句可以省略大括號不寫。
技 術 無 他, 唯 有 熟 爾。
知 其 然, 也 知 其 所 以 然。
踏 實 一 些, 不 要 着 急, 你 想 要 的 歲 月 都 會 給 你。