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