Java8 lambda 表達式初體驗上
lambda 表達式,是一段可以傳遞的代碼,可以被多次執行。在 java8 之前,如果我們想寫一個簡單的比較器 Compartor ,我們需要創建一個實現類或者一個匿名內部類類傳入到需要比較的方法內當中。
在 java8 之前傳遞一段代碼不是很容易,現在我們想要實現一個通過傳遞代碼來檢查某個字符串的長度是否小于另外一個字符串的長度。
(String first, String second) -> Integer.compare(first.length(), second.length());
上面這段代碼就是 lambda 表達式,這個表達式不僅僅是一個簡單的代碼塊,還必須指定傳遞給代碼的所有變量。
Java 當中 lambda 表達式的格式是:參數、箭頭(->)、以及一個表達式。如果負責計算的代碼無法用一個表達式表示,可以使用 {} 括起來。
如果 lambda 沒有參數,可以使用 () 來表示,如果 lambda 表達式的參數類型可以被推導,那么可以省略掉。
Comparator<String> comparator = (first, second) -> Integer.compare( first.length(), second.length());
上面的例子當中會推導出 first 和 second 的類型是 String ,因為表達式賦值給了一個字符串比較器。
注意,在 lambda 表達式當中只在某些分支有返回值是不合法的。
函數式接口
Java 當中有許多接口都需要封裝代碼塊, Runnable 、 Compartor 等等。
對于只包含一個方法的接口,可以通過 lambda 表達式來創建該接口的對象,這種接口被稱為函數式接口。
在 java.util.function 包下面提供了許多通用的函數式接口。
可以在任意函數式接口上面使用 @FunctionalInterface 來標識它是一個函數式接口,但是該注解不是強制的。
當 lambda 表達式被轉換成一個函數式接口的實例時,需要注意處理檢查時異常,如下代碼。
Runnable runnable = () -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
};如果不加 try catch 語句的話,這個賦值語句就會編譯錯誤,因為 Runnable 的 run 方法是沒有異常拋出的。
Callable 是可以拋出任何異常,并且有返回值,但是我們不想返回任何數據的時候可以如下定義:
Callable<Void> callable = () -> {
System.out.println("xxx");
return null;
};方法引用
有時候,我們想傳遞的代碼已經有現成的實現了。例如,我們僅僅想點擊按鈕時候打印 event 對象,可以進行如下代碼:
button.setOnAction(System.out::println);
表達式 System.out::println 是一個方法引用,等同于 lambda 表達式 x -> System.out.println(x);
:: 操作符將方法名和對象或類的名字分隔開。有以下三種主要的使用情況:
- 對象 :: 實例方法
- 類 :: 靜態方法
- 類 :: 實例方法 </ul>
前兩種情況,方法引用相當于提供方法參數的 lambda 表達式。 System.out::println 等同于 x -> System.out.println(x);
Math::pow 等同于 (x, y) -> Math.pow(x, y);
第三種情況,第一個參數會成為執行方法的對象。例如, Sting::compareToIgnoreCase 等同于 (x, y) -> x.compareToIgnoreCase(y);
Comparator<String> comparator = String::compareTo;
當然還可以捕獲 this 指針,this :: equals 相當于 x -> this.equals(x);
【參考資料】