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標識符指的是外部調用者
		 */
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章