java8的lambda表示式及方法引用(一)
當前很多公司的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識別符號指的是外部呼叫者
*/
}
}