Java 8 中的 Lambda 表達式
Lambda 表達式是 Java 8 最受歡迎的功能。人們將函數式編程的概念引入了 Java 這門完全面向對象的命令式編程語言。關于函數式編程是如何運作的,這個話題超出了本文的范圍,不過我們會提煉出它一個明顯有別于我們所經常使用的 OOP (面向對象編程)的功能來加以討論。
在本文中, 我們將了解到 lambda 表達式具體是什么東西,還有就是它們是如何將自己融入整個 Java 生態系統的。我們也會對沒有使用 lambda 表達式的代碼以及后面使用 lambda 進行重構的示例代碼進行一下觀察和比較。
了解 Lambda 表達式
Lambda 表達式是一塊我們可以將其傳入并執行的代碼。對于作為 Java 程序員的我們而言,并不會怎么習慣將一塊代碼傳入一個函數這樣的方式。我們的習慣是將定義的代碼封裝到方法體里面,然后通過對象引用來加以執行,如下所示:
public class LambdaDemo {
public void printSomething(String something) {
System.out.println(something);
}
public static void main(String[] args) {
LambdaDemo demo = new LambdaDemo();
String something = "I am learning Lambda";
demo.printSomething(something);
}
}
這是經典 OOP 開發范式的風格,將方法實現對調用者隱藏。調用者只是簡單地向方法傳入一個變量,然后方法拿這個變量會執行一些操作,并返回另外一個變量值,或者如我們的示例所示,會產生一些副作用效果。
現在我們要來看看一種使用了行為傳遞方式,而不是變量傳遞的等效實現。為此,我們要創建一個函數式的接口,里面定義的是對行為,而不是對方法的抽象。一個函數式接口是一種只有一個方法的接口:
public class LambdaDemo {
interface Printer {
void print(String val);
}
public void printSomething(String something, Printer printer) {
printer.print(something);
}
}
在上面的代碼實現中, Printer 接口負責所有的打印操作。 printSomething 方法不再對行為進行定義,而是執行由 Printer 定義的行為:
public static void main(String[] args) {
LambdaDemo demo = new LambdaDemo();
String something = "I am using a Functional interface";
Printer printer = new Printer() {
@Override
public void print(String val) {
System.out.println(val);
}
};
demo.printSomething(something, printer);
}
讀者中比較有觀察能力的可能已經注意到,我并沒有在這里做什么新的事情。的確是這樣的,因為我還沒有應用到 lambda 表達式。我們只是簡單地創建了一個 Printer 接口的具體實現,并將它傳入了 printSomething 方法。
上面的示例旨在給我們帶來一個將 Lambda 表達式引入到 Java 中的關鍵目標:
Lambda 表達式原被用于定義一個函數式接口的內聯實現。
在我們使用 lambda 表達式對上面的示例進行重構之前,先來學習一下必要的語法知識:
(param1,param2,param3...,paramN) - > {//代碼塊;}
一個 lambda 表達式的組成,是一個我們通常會定義在方法聲明中的,以括弧封閉起來并以逗號分隔的參數列表,后面跟上一個箭頭標記指向要執行的代碼。現在,讓我們來使用 lambda 對上面的代碼進行重構:
public static void main(String[] args) {
LambdaDemo demo = new LambdaDemo();
String something = "I am learning Lambda";
/**/
Printer printer = (String toPrint)->{System.out.println(toPrint);};
/**/
demo.printSomething(something, printer);
}
看上去非常緊湊且美觀。因為函數式接口只聲明了一個方法,所以在 lambda 的第一部分中傳入的參數被自動地映射到了方法的參數列表上,而箭頭右邊的代碼則被當做是方法的具體實現了。
為什么要使用 Lambda 表達式
如同前面的示例, lambda 表達式能讓我們擁有更加緊湊的代碼,更加易于閱讀和跟蹤。這個在性能和多核處理方法還有其它的一些好處,不過它們得在你了解了 Streams API 以后才有用,而這個超出了本文的范圍。
通過比較使用和沒使用 lambda 的 main 方式實現,當它一下子把代碼變得簡短的時候,我們切實地看到了 lambda 表達式的能力:
public static void main(String[] args) {
LambdaDemo demo = new LambdaDemo();
String something = "I am learning Lambda";
/**/
Printer printer = (String toPrint)->{System.out.println(toPrint);};
/**/
demo.printSomething(something, printer);
}
我們還可以讓代碼比這里所展示的更簡潔。這樣的事情發生時,你甚至無需指定箭頭左邊參數的類型,而其類型會由編譯器根據接口方法的形參推斷出來。
Printer printer = (toPrint)->{System.out.println(toPrint);};
我們還可以做得更好。lambda 的另外一個特性就是: 如果只有一個參數, 就可以將括弧完全消除掉。同樣的,如果在箭頭右邊只有一條語句,也可以將大括號去掉:
Printer printer = toPrint -> System.out.println(toPrint);
現在的代碼看起來真正變得可愛起來,不過我們才剛剛開始而已。如果我們的接口方法并不要任何參數,那就可以將生命用一對空的括弧替換掉:
() -> System.out.println("anything");
如果我們只是內聯一個 lambda 進去,而不去首先創建一個對象然后將其傳入到 saySomething 方法,會如何呢:
public static void main(String[] args) {
LambdaDemo demo = new LambdaDemo();
String something="I am Lambda";
/**/
demo.printSomething(something, toPrint -> System.out.println(toPrint));
}
現在我們才是真的在談論函數式編程了。我們的 main 函數體從一開始的 9 行代碼減少到了 3 行。這樣緊湊的代碼使得 lambda 表達式對于 Java 程序員非常有吸引力。
總結
在本文中,我們對 Java 中的 Lambda 表達式進行了簡單介紹,了解了它們可以被用來提升函數式接口實現的代碼質量。關注這個網站可以獲得有關 Lambda 的更多知識,因為我還會在這里涉及 Stream API 的內容,并對其如何同 Collections 框架結合在一起使用來給予我們更多 Lambda 的好處進行討論。
來自:https://www.oschina.net/translate/lambda-expressions-in-java-8