JDK8新特性學習(一) Lambda表示式和函式式介面
Lambda表示式和函式式介面
剛進公司時,公司正處於由JDK7換用JDK8的時間短,之所以更換JDK版本,聽說是公司業務中需要用到JDK8的一些新特性。鑑於我現在也無事可做,姑且來學習總結一下JDK8的一些特性吧。水平有限,這篇勉強算是對他人部落格上零散內容的一個總結。
1. Lambda表示式
Lambda表示式 匿名函式,當需要一個函式而又不想給他一個命名時,在java中,對於那些只使用一次的方法使用這種方式,能夠減少命名上的負擔。
允許將行為傳入函式,取代匿名類。很經典的就是一個實現Runnable介面的例子,之前很長一段時間用的是匿名內部類,現在有了lambda表示式來使用。
//使用匿名內部類
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("The old runable now is using!");
}
}).start();
//使用lambda表示式
new Thread(() -> System.out.println("It's a lambda function!")).start();
減少了很多程式碼量,也使得程式碼結構更加清晰。
允許使用函式式風格程式設計,將函式當成引數傳遞給某個方法,或者把程式碼本身當作資料處理
結構寫法上,lambda表示式由三部分組成: (引數列表),符號 -> ,函式體(多個語句時加上{})。可以訪問類的成員變數和區域性變數,但是會轉為final。
具體的一些匿名函式的使用,由於不太能用到所以不過多說明,僅舉部分例子來作為使用時寫法的參考,以集合類的遍歷為例,雖然用之前的寫法也不復雜。之所以選擇集合類就是因為很熟悉,不用寫原先的遍歷方法出來,也能很好的對比兩種寫法的差異。
//List的遍歷
List<String> list = new ArrayList<>();
list.add("aaa");
...
...
list.forEach(x -> System.out.println(x));
//Map的遍歷
LinkedHashMap<Integer,Integer> lhm = new LinkedHashMap<>();
lhm.put(1 , 4);
...
...
lhm.forEach((k,v) -> System.out.println("key:" + k + " value:" + v));
2. 函式式介面
函式式介面是SAM(Single Abstract Method )型別的介面,是為了讓現有功能能和Lambda表示式能夠良好相容所想出的方法。
定義了這種型別的介面,使得以其為引數的方法,可以在呼叫時,使用一個lambda表示式作為引數。換個角度說就是,當我們呼叫一個方法,可以傳入lambda表示式作為引數,那麼這個方法的引數型別,必定是一個函式式的介面。
就是指只有一個函式的介面,這樣的介面可以被隱式轉換為Lambda表示式。例如,java.lang.Runnable
和 java.util.concurrent.Callable
等。
但是函式介面程式碼層面十分脆弱,只要這個介面中有其他的函式就會編譯失敗,為了解決函式介面在實際使用過程中的脆弱性。採用顯式說明的方式,jdk8提供了一個@FunctionalInterface
這個註解來進行宣告。
不過預設方法和靜態方法不會破環函式式介面的定義。
舉上面提到的兩個jdk中程式碼的例子:
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
上面兩個都是函式式介面的寫法,然後我們來對比一下使用lambda和不使用lambda表示式的寫法差別:
//不使用Lambda表示式時
Runnable runnable1=new Runnable(){
@Override
public void run(){
System.out.println("RunningwithoutLambda");
}
};
//使用Lambda表示式的寫法
Runnable runnable2=()->{
System.out.println("RunningfromLambda");
};
3. 其他
其他什麼predicate,stream之類的以後有機會有時間再來補充討論。