1. 程式人生 > >JDK8新特性學習(一) Lambda表示式和函式式介面

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.Runnablejava.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之類的以後有機會有時間再來補充討論。