Java 8 和 Scala 中的 Lambda 表達式

這篇文章是infoQ上面關於java 8 和 scala 特性比較的一部分,原文實在是太長了,,分段翻譯,先貼出來一部分,翻譯的很差,歡迎拍磚。。。原文地址 

Java8 終於要支持Lambda表達式!自2009年以來Lambda表達式已經在Lambda項目中被支持。在那時候,Lambda表達式仍被稱爲Java閉包。在咱們進入一些代碼示例之前,先來解釋下爲何Lambda表達式在Java程序員中廣受歡迎。

一、爲何使用Lambda表達式

Lambda表達式一般使用在圖形用戶界面(GUI)的開發中。通常來講,GUI編程將程序行爲和事件作鏈接。好比,當用戶按下一個按鈕(觸發一個事件),你的程序就須要去執行某些行爲,多是將一些數據儲存到一個數據存儲器中。在Swing中,可使用ActionListener來實現:
class ButtonHandler implements ActionListener {
	public void actionPerformed(ActionEvent e) {
		//do something
	}
}

class UIBuilder {
	public UIBuilder() {
		button.addActionListener(new ButtonHandler());
	}
}

這個例子代表了 ButtonHandler 類做爲一個回調替換的用法。在這裏 ButtonHandler 類僅包含 ActionListener 接口定義的 actionPerformed 方法。咱們可使用匿名內部類來簡化代碼:
class UIBuilder {
	public UIBuilder() {
		button.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				//do something
			}
		})
	}
}

這樣代碼簡潔多了。更仔細的去看代碼時,就會發現咱們還建立一個只生成一個實例的類,而這個實例也僅僅持有一個獨立的方法。這剛好是Lambda表達式所能解決的其中一類問題。

二、Lambda表達式代替函數

一個lambda表達式從字面上講就是一個函數。它定義了一個函數的輸入參數和函數體。Java 8 中的,lambda表達式語法還沒有肯定,不過大體應該相似這個樣子的:
(type parameter) -> function_body

一個具體的例子:
(String s1, String s2) -> s1.length() - s2.length();

這個lambda表達式用來計算兩個字符串的長度差。還有一些擴展的語法,好比避免參數的類型定義(咱們立刻見看到例子)還有使用{和}來支持多行定義。
Collections.sort() 方法是lambda表達的理想例子。它容許咱們將字符串按照長度排序:
List<String> list = Array.asList("loooooong", "short", "tiny");
Collections.sort(list, (String s1, String s2) -> s1.length() - s2.length());
> "tiny", "short", "loooooong".

因此,不像如今java必需要求的向sort方法輸入一個已經實現的Comparator(比較器)而是傳送一個lambda表達式咱們就能夠獲得相同的結果。

三、Lambda表達式代替閉包

lambda表達式有許多有趣的特性。其中之一是,它們是閉包。一個閉包容許函數訪問直接詞法做用域以外的變量。
String outer = "java 8"
(String s1) -> s1.length() - outer.length()

在例子中,lambda表達式訪問了字符串 outer 這個做用域以外定義的變量。對於內聯閉包來講這是很難作到的。

四、Lambda表達式也支持類型推論

類型推論是java 7 引入的但它一樣適用於lambda表達式。簡單來講,類型推論意味着程序員能夠在任意一個編譯器可以自動推斷出類型的地方省略類型定義。
若是類型推論可以應用到前面的排序lambda表達式上,那麼它就能寫成下面的樣子:
List<String> list = Arrays.asList(...);
Collections.sort(list, (s1, s2) -> s1.length()-s2.length());

就像你所見到的同樣,參數s1和s2的類型被省略了。由於編譯器知道list是一個字符串集合,它知道被用來做爲比較器的lambda表達式一定是相同的類型。所以,這個類型不須要顯式地聲明,即便你有這麼作的自由。
類型推論的主要優點就是減小樣板代碼,若是編譯器能夠爲咱們識別類型,爲何咱們必須本身定義它們。

五、珍愛Lambda表達式,遠離匿名內部類

咱們來體會下,爲什麼lambda表達式和類型推論有助於簡化咱們前面所提到的回調例子:
class UIBuilder {
	public UIBuilder() {
		button.addActionListener(e -> //process ActionEvent e)
	}
}

咱們下載直接傳送一個lambda表達式進入 addActionListener 方法來代替前面定義的持有回調方法的類。除了減小模板代碼和提升可讀性之外,它使咱們直接表達咱們惟一感興趣的事情:處理事件。
在咱們瞭解lambda表達式更多優點以前,先來看看在Scala中的lambda表達式副本。

六、Scala中的Lambda表達式

在函數式編程中,函數是基本的構造塊。Scala融合了java中的面向對象編程和函數式編程。在Scala中,一個lambda表達式是種叫作「函數」或者「函數文本」。Scala中的函數屬於一等公民。它們能夠被分配給vals或者vars(最終變量或者非最終變量),它們能夠做爲其餘函數的參數,也能夠組合成新的函數。
在Scala中一個函數文本寫成以下形式:
(argument) => //funtion body

舉例來講,前面提到的java 用來計算兩個字符串長度差的 lambda 表達式,在Scala中寫做以下:
(s1: String, s2 :String) => s1.length - s2.length

Scala中的函數文本也是閉包。它能夠訪問在直接詞法做用域以外定義的變量。
val outer =10
val myFuncLiteral = (y: Int) => y * outer
val result = myFuncLiteral(2)
> 20

這個例子結果是20.
正如你所見,咱們將函數文本分配給了變量 myFuncLiteral。
java 8 的lambda表達式和Scala的函數文本在語法和語義上的類似性是十分明顯的。從語義上講它們是相同的,而語法上的惟一不一樣就是箭頭符號(java8 ->, scala =>)和咱們沒有提到的簡化符號。
相關文章
相關標籤/搜索