lambda表達式,這是這些年來Java語言最讓人激動的一個變化。
爲什麼引入lambda表達式
lambda表達式是一個可傳遞的代碼塊,可以在以後執行一次或多次。具體介紹語法之前,我們先退一步,觀察一下我們在Java中的哪些地方用過這種代碼塊。
之前我們瞭解瞭如何按指定時間間隔完成工作。將這個工作放在一個ActionListener的actionPerformed方法中:
class Worker implements ActionListener {
public void actionPerformed(Action event) {
...
}
}
想要反覆執行這個代碼時,可以構造Worker類的一個實例。然後把這個實例提交到一個Timer對象。這裏的重點是actionPerformed方法包含希望以後執行的代碼。
或者可以考慮如何用一個定製比較器完成排序。如果想按長度而不是默認的字典順序對字符串排序,可以想sort方法傳入一個Comparator對象:
class LengthComparator implements Comparator<String> {
public int compare(String first, String second) {
return first.length() - second.length();
}
}
...
Arrays.sort(strings, new LengthComparator());
compare方法不是立即調用。實際上,在數組完成排序之前,sort方法會一直調用compare方法,只要元素的順序不正確就會重新排列元素。將比較元素所需的代碼放在sort方法中,這個代碼將於其餘的排序邏輯繼承。
這兩個例子有一些共同點,都是將一個代碼塊傳遞到某個對象(一個定時器,一個sort方法)。這個代碼塊會在將來某個時間調用。
到目前爲止,在Java中傳遞一個代碼段並不容易,不能直接傳遞代碼段。Java是一種面嚮對象語言,所以必須構造一個對象,這個對象的類需要有一個方法能包含所需的代碼。
在其他語言中,可以直接處理代碼塊。Java設計者很長時間以來一直拒絕增加這個特性,畢竟,Java的強大之處就在於其簡單性和一致性。如果只要一個特性能夠讓代碼稍簡潔一些,就把這個特性增加到語言中,這個語言很快就會變得一團糟,無法管理。不過,在另外那些語言中,並不只是創建線程或註冊按鈕點擊事件處理器更容易;它們的大部分API都很簡單、更一致而且更強大。在Java中,也可以編寫類似API利用類對象實現特定的功能,不過這種API使用可能很不方便。
就現在來說,問題已經不是是否增強Java來支持函數式編程,而是要如何做到這一點。設計者們做了多年的嘗試,終於找到一種適合Java的設計。
lambda表達式的語法
我們考慮一下剛纔說的排序例子。我們傳入代碼來檢查一個字符串是否比另一個字符串短:
first.length() - second.length();
first和second是什麼呢?它們都是字符串,Java是一種強類型語言,所欲我們還要指定它們的類型:
(String first, String second) -> first.length() - second.length();
這就是你看到的第一個lambda表達式。lambda表達式就是一個代碼塊,以及必須傳入代碼的變量規範。
你已經見過Java中的一種lambda表達式形式:參數,箭頭(->)以及一個表達式。如果代碼要完成的計算無法放在一個表達式中,就可以像寫方法一樣,把這些代碼放在{}中,幷包含顯式的return語句。如:
(String first, String second) - > {
if (first.length() < second.length()) return -1;
else if (first.length() > second.length()) return 1;
else return 0;
}
即使lambda表達式沒有參數,仍然要提供空括號,就像無參數方法一樣:
() -> {
for (int i = 100; i >=0; i--)
System.out.println(i);
}
如果可以推導出一個lambda表達式的參數類型,則可以忽略其類型。如:
Comparator<String> comp = (first, second) -> first.length() - second.length();
在這裏,編譯器可以推導出first和second必然是字符串,因爲這個lambda表達式將賦給一個字符串比較器。
如果方法只有一個參數,而且這個參數的類型可以推導得出,那麼甚至還可以省略小括號:
ActionListener listener = event -> System.out.println("The time is " + new Date());
無需指定lambda表達式的返回類型。lambda表達式的返回類型總是會由上下文推導得出,如:
(String first, String second) -> first.length() - second.length();
可以在需要int類型結果的上下文中使用。
實例
package cn.freedompc.lambda;
import java.util.Arrays;
import java.util.Date;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class LambdaTest {
public static void main(String[] args) {
String[] planets = new String[] {"Mercury", "Venus", "Earth", "Mars",
"Jupiter", "Saturn", "Uranus", "Neptune"};
System.out.println(Arrays.toString(planets));
System.out.println("Sorted in dictionary order:");
Arrays.sort(planets);
System.out.println(Arrays.toString(planets));
System.out.println("Sorted by length:");
Arrays.sort(planets, (first, second) -> first.length() - second.length());
System.out.println(Arrays.toString(planets));
Timer t = new Timer(1000, event -> System.out.println("The time is " + new Date()));
t.start();
JOptionPane.showMessageDialog(null, "Quit program");
System.exit(0);
}
}
結果:
捐贈
若你感覺讀到這篇文章對你有啓發,能引起你的思考。請不要吝嗇你的錢包,你的任何打賞或者捐贈都是對我莫大的鼓勵。