1. 程式人生 > >jdk8 新特性lambda表示式

jdk8 新特性lambda表示式

首先說明下,jdk8的新特性forEach,Stream在遍歷集合時,程式碼看上去簡潔些,但效率會變低

好了,今天開始介紹新特性,先說lambda表示式

Python裡有個匿名函式,用lambda定義,jdk8的lambda表示式就相當於一個匿名函式,只是功能強大一些

先說一個概念:

函數語言程式設計:

函數語言程式設計是種程式設計正規化。是相對於指令式程式設計(常見於面向過程,如C語言),指令式程式設計是編寫,理解和除錯程式碼最容易的方法

舉例說明:獲取BufferedReader物件

指令式程式設計:

InputStream in=new InputStream("d:\\test.txt");
InputStreamReader isr=new InputStreamReader(in);
BufferedReader br=new BufferedReader(isr);

函式事程式設計:呼叫函式替代命令

BufferedReader br = new BufferedReader(new InputStreamReader(in))

 函式式介面(Functional Interface):

jdk8中新增了函式式介面,

函式式介面就是一個有且僅有一個抽象方法,但是可以有多個非抽象方法的介面(修飾符為defalut)。

以前認識的介面中所有方法必須都是抽象的,是不能有非抽象方法的,jdk更新過程中可能對某些介面進行擴充套件,但是如果在原有介面中加入抽象方法,那實現了該介面的類要全部重新寫,為了解決更新介面但相容以前版本的程式,就可以在函式式介面中可以增加defalut方法

Lambda 表示式和方法引用(實際上也可認為是Lambda表示式)就是針對函式式介面使用的.因為lambda表示式沒有方法名,所以針對的就是介面中的抽象方法,說明函式值介面中只能有一個抽象方法,不然天知道lambda重寫的是哪個抽象方法

以前如果引數是介面型別的例項,要麼自定義類實現介面,要麼用匿名內部類,那lambda表示式的引入就可以讓匿名內部類的編寫變得簡潔一些.

函式式介面,如Callable介面(java.util.concurrent.Callable)。

jdk8中新增了@FunctionalInterface註解來顯示標註一個函式式介面,並不是所有函式式介面都被標註出來了。該註解主要用於編譯級錯誤檢查,加上該註解後,如果自定義介面不符合函式式介面的定義,會報錯。當然有沒有該註解不會影響是不是函式式介面的本質.

註解樣式如下:

@FunctionalInterface
public interface Callable<V> {
   
    V call() throws Exception;
}

defalut方法

jdk8中允許介面中定義非抽象方法,在介面中的非抽象方法上使用default修飾即可,加入defalut方法是對介面的補充,好處就是提高程式的相容性.介面中定義defalut方法變相讓java支援多繼承,因為可實現多個介面

實際上函式式介面可支援靜態方法,繼承自java.lang.Object類要重寫的public方法,


lambda表示式

上面已經說過,lambda表示式只能用在重寫函式式介面的抽象方法上,因為函式式介面只有一個抽象方法,編譯器會認為lambda表示式寫的方法就是介面的唯一的抽象方法

先看lambda的格式:

(型別 引數, 型別 引數, …, 型別 引數) -> {  程式碼塊;  return 結果; }
注:引數型別可省略,編譯器可以從上下文環境推斷出lambda表示式的引數型別,故可以省略
  如箭頭右邊只有一條語句,則右邊的一對大括號可省略
  當lambda表示式只有一個引數時,可以省略左邊的小括號
  對有返回值的抽象方法,如果重寫只有一行語句,可以省略掉return關鍵字,(同時必須省略一對大括號)

   

格式形如為

( )->{ } 
括號 向右的箭頭 大括號(方法體)

示例:

自定義函式式介面


@FunctionalInterface
public interface MyInter {
	int add(int a, int b);

	// defalut修飾的方法
	default void sub(int a, int b) {
		System.out.println(a - b);
	}

	// 可寫靜態方法
	static String addString(String s1, String s2) {
		return s1 + s2;
	}

	// 重寫繼承自Object類的方法,必須是抽象方法,再被實現該介面的類重寫
	// 這種繼承自Object類的方法,不被介面認定為抽象方法(實際是抽象方法)
	@Override
	boolean equals(Object obj);
}

測試類:

public class Test01 {
	public static void main(String[] args) {
		//傳統匿名內部類的寫法
		MyInter mi = new MyInter() {
			@Override
			public int add(int a, int b) {
				int temp = a + b;
				return temp;
			}
		};
		System.out.println(mi.add(1, 2));
		
		//試用lambda表示式寫匿名內部類
		MyInter mi2 = (a, b) -> {
			return a + b;
		};
		System.out.println(mi2.add(1, 2));
                // 省略return語句
		MyInter mi3 = (a, b) -> a + b;
		System.out.println(mi3.add(1, 2));
	
	}
}
out:
3
3
3

lambda表示式寫多執行緒示例

public class Test02 {
	public static void main(String[] args) {
		// 以前寫法
		Thread t1 = new Thread(new Runnable() {
			@Override
			public void run() {
				for (int i = 0; i != 10; i++) {
					System.out.println(Thread.currentThread().getName() + " : " + i);// 列印0-9,包括9
				}
			}
		}, "t1");
		t1.start();
		// 用lambda表示式下多執行緒
		Thread t2 = new Thread(() -> {
			for (int i = 0; i < 10; i++) {
				System.out.println(Thread.currentThread().getName() + " : " + i);
			}
		}, "t2");
		t2.start();

	}
}
out:
t1 : 0
t1 : 1
t1 : 2
t1 : 3
t1 : 4
t1 : 5
t1 : 6
t1 : 7
t1 : 8
t1 : 9
t2 : 0
t2 : 1
t2 : 2
t2 : 3
t2 : 4
t2 : 5
t2 : 6
t2 : 7
t2 : 8
t2 : 9

 

參考:http://www.monkey1024.com/javase/706