當前很多公司的java開發環境都升級到jdk8以上了。lambda表達式是java8中最重要的更新,其目的是爲了配合隨着並行運算流行起來的所謂“函數式”編程改進而來的語法糖。既然是語法糖,那麼其實不用這些lambda表達式也是可以實現原有功能的,只不過看起來代碼行數多一些而已。
簡單說一下對lambda表達式的理解:lambda表達式其實就是“內部匿名類”對象的特定方法的實現代碼。這個內部匿名類實現了某個特定接口(由註解@FunctionalInterface標註的)。這個帶@FunctionalInterface註解的接口只能有一個方法(否則就不知道lambda表達式要幹什麼事了)--嚴格來說是只能有一個抽象方法,因爲現在允許接口裏有默認實現了,帶默認實現那些不算。還是用代碼描述更清楚:
假定一個接口定義:
@FunctionalInterface
public interface LamDemo {
int operation(int a,int b);
}
如果不加@FunctionalInterface註解,那麼就是一個普通接口,加上了裏面的(抽象)方法就只能有一個。上面例子是一個名爲operation的方法,兩個整數參數,返回值也是整數。
最普通的用法,就是寫一個類實現這個接口,然後用的時候創建這個類的對象:
//普通非匿名類實現接口LamDemo
class TempClass implements LamDemo{
@Override
public int operation(int a, int b) {
return a+b;
}
}
用的時候:
//普通對象,常規用法
private LamDemo ldTemp = new TempClass();
匿名類就爲了省一點事,不去定義這個TempClass,直接用接口創建對象:
//創建匿名類對象賦予接口類型的變量
private LamDemo _ld = new LamDemo(){
@Override
public int operation(int a, int b) {
return a+b;
}
};
效果等同。
用lambda表達式更進一步,連new這個操作也隱含了:
//在變量中使用lambda表達式
private LamDemo ld=(int a ,int b)-> a+b;
隱含的意思是創建了一個對象,這個對象的類實現了LamDemo接口定義的方法,實現代碼是a+b。這樣就明白爲啥接口只能有一個方法了,否則編譯器不知道對應哪個。實現代碼的規則是這樣的()->{},左邊是方法參數,右邊是方法體。這是標準寫法,但爲啥感覺看到的lambda表達式五花八門似的。這就涉及各種各樣的所謂“簡化規則”。按標準寫法上面的例子其實應該寫成這樣:
//在變量中使用lambda表達式
private LamDemo ld=(int a ,int b)->{return a+b;};
簡化規則如下:
參數可以是零個或多個,零個時左邊就是一個空()
參數類型可指定,也可省略(因爲接口方法定義裏已經說了參數類型了)
參數包含在圓括號中,用逗號分隔,一個參數時可省略()
表達式主體可以是零條或多條語句,包含在花括號中,只有一條語句時可省略{}
表達式主體有一條以上語句時,表達式的返回類型與代碼塊的返回類型一致
表達式只有一條語句時,表達式的返回類型與該語句的返回類型一致
總之就是能犯懶就犯懶,少敲幾個字母是幾個字母,代價就是初學看起來有點暈。
既然lambda表達式實際上是個匿名對象,那麼它就可以賦給變量(上面例子);
可以當作參數傳給方法:
//lambda表達式作爲方法參數
System.out.println(t.lambdaReturn1(3,5,(a,b)->a*b));
還可以用作方法返回值:
//在返回值中應用lambda expression
public LamDemo lambdaReturn2(){
return (int a,int b)->a*b;
}
完整示例代碼:
//普通非匿名類實現接口LamDemo
class TempClass implements LamDemo{
@Override
public int operation(int a, int b) {
return a+b;
}
}
public class Test {
//普通類對象
private LamDemo ldTemp = new TempClass();
//匿名類對象
private LamDemo _ld = new LamDemo(){
@Override
public int operation(int a, int b) {
return a+b;
}
};
//在變量中使用lambda表達式
private LamDemo ld=(int a ,int b)->a+b;
//在參數中使用lambda表達式(見後面調用)
public int lambdaReturn1(int source,int target,LamDemo lr){
return lr.operation(source, target);
}
//在返回值中應用lambda expression
public LamDemo lambdaReturn2(){
return (int a,int b)->a*b;
}
//省略參數類型定義
private LamDemo ld1=(a ,b)-> a+b;
public static void main(String[] args){
Test t=new Test();
System.out.println(t.ld.operation(3, 5));
System.out.println(t.ld1.operation(6, 6));
//lambda表達式作爲方法參數
System.out.println(t.lambdaReturn1(3,5,(a,b)->a*b));
//方法返回值是個lambda表達式(是個對象)
System.out.println(t.lambdaReturn2().operation(5,7));
//lambda表達式方式創建新線程並運行(lambda expression作爲實現Runnable接口的對象傳給Thread的構造函數,其對應唯一方法是void run(),無參數無返回值)
new Thread(()->System.out.println("lambda expression thread run")).start();
/*
* 總結:lambda表達式就是把一段代碼作爲內部類的對象的某個特定實現(編譯器所推導出的函數接口)
* lambda expression實際上是用內部類實現的,所以傳過來的參數默認是final的,不可修改
* lambda表達式與匿名內部類的區別在於this標識符:在匿名內部類中使用this指的是此內部類;
* 而在lambda表達式中的this標識符指的是外部調用者
*/
}
}