Java 8 發(fā)布帶來(lái)的一個(gè)主要特性就是對(duì)函數(shù)式編程的支持。
而 Lambda 表達(dá)式就是一個(gè)新的并且很重要的一個(gè)概念。
它提供了一個(gè)簡(jiǎn)單并且很簡(jiǎn)潔的編碼方式。
首先從幾個(gè)簡(jiǎn)單的 Lambda 表達(dá)式的例子開(kāi)始了解 Java 中的函數(shù)式編程。
Lambda 表達(dá)式初識(shí):
首先定義一個(gè) Lambda 表達(dá)式:
x -> x + 1
這個(gè)表達(dá)式輸入?yún)?shù)是一個(gè) x,然后對(duì)這個(gè)參數(shù) x 的操作是加 1,然后將這個(gè)結(jié)果返回,即返回值。
從這個(gè)簡(jiǎn)單的 Lambda 表達(dá)式可以看出 Lambda 表達(dá)式的語(yǔ)法格式是:
(類(lèi)型 參數(shù)1, 類(lèi)型 參數(shù)2) -> { 方法體 }
參數(shù)的小括號(hào)可以省略不寫(xiě);
方法體的花括號(hào)也可以省略不寫(xiě)(這是因?yàn)榉椒w有兩種類(lèi)型:?jiǎn)涡写a 或者是 代碼塊,單行代碼不需要花括號(hào)同時(shí) return 關(guān)鍵字省略),例如:
(int x, int y) -> { return x + y; }
(int x, int y) -> x + y
x -> x + 1
() -> 3.14
(String s) -> { System.out.println(s); }
第一個(gè)表達(dá)式接收兩個(gè)參數(shù) x 和 y,返回 x + y;
第二個(gè)表達(dá)式和第一個(gè)表達(dá)式一樣,省略了花括號(hào)和 return 關(guān)鍵字;
第三個(gè)表達(dá)式接收一個(gè)參數(shù),返回 x+1;
第四個(gè)表達(dá)式不接收任何參數(shù),返回?cái)?shù)字 3.14;
第五個(gè)表達(dá)式接收一個(gè)參數(shù),沒(méi)有返回值。
看到第三個(gè)表達(dá)式,很多新接觸 Lambda 表達(dá)式的朋友不免會(huì)有兩個(gè)疑問(wèn):x 的類(lèi)型是什么?這個(gè)整個(gè)函數(shù)的類(lèi)型是什么呢,怎么表示它?
接下來(lái)就要引入另一個(gè)關(guān)鍵的內(nèi)容,即 java.util.function 包,官方對(duì)它的定義是:“Functional interfaces provide target types for lambda expressions and method references. ” 即為定義函數(shù)對(duì)象提供的類(lèi),也就是如何存儲(chǔ)一個(gè)函數(shù)對(duì)象。也就是它專(zhuān)門(mén)用來(lái)解決上面提出的這個(gè)問(wèn)題:
回到剛剛的這個(gè) Lambda 表達(dá)式:x -> x + 1,這個(gè)表達(dá)式接收一個(gè)參數(shù),返回一個(gè)參數(shù),我們可以將這個(gè) Lambda 表達(dá)式表示為:
Function<Integer, Integer> add = x -> x + 1;
Function<String, String> concat = x -> x + 1;
第一行代碼里的 x 的類(lèi)型是 Integer,它表示將 Integer 類(lèi)型的參數(shù) x 加 1 然后并返回,即如果參數(shù)是 2,那么這行代碼返回 3。
第二行代碼里的 x 的類(lèi)型是 String,它表示將 String 類(lèi)型的參數(shù) x 和 "1" 連接并返回,即如果參數(shù)是 "hi", 那么這行代碼返回 hi1。
兩個(gè)參數(shù):
如果我們需要定義兩個(gè)參數(shù)的函數(shù)要怎么寫(xiě)呢?比如將兩個(gè) Integer 類(lèi)型的 x,y 進(jìn)行求和并返回結(jié)果?
這里我們需要另一個(gè)類(lèi) BiFunction<T, U, R>,T表示第一個(gè)輸入?yún)?shù)的類(lèi)型,U表示第二個(gè)輸入?yún)?shù)的類(lèi)型,R表示返回值的類(lèi)型,所以我們的答案是:
BiFunction<Integer, Integer, Integer> sum = (x, y) -> x + y;
只輸入?yún)?shù)不返回結(jié)果:
如果我們需要定義一個(gè)只輸入?yún)?shù)卻不返回結(jié)果的函數(shù)要怎么寫(xiě)?這里我們需要另一個(gè)類(lèi) Consumer<T>:
Consumer<String> sayHi = name -> System.out.println("hi, " + name);
如果想要定義輸入兩個(gè)參數(shù)卻不返回結(jié)果的函數(shù)需要用 BiConsumer<T, U> 類(lèi),用法和前面提到的 BiFunction 類(lèi)型一樣,不再贅述。
只返回結(jié)果不輸入?yún)?shù):
如果我們需要定義一個(gè)只返回結(jié)果但不需要輸入?yún)?shù)的函數(shù)要怎么寫(xiě)?這里我們需要另一個(gè)類(lèi) Supplier<T>:
Supplier<String> getName = () -> "Carl";
如何執(zhí)行函數(shù):
既然有了函數(shù),那么這些函數(shù)要怎么執(zhí)行呢?
答案是用 apply() 方法:
Integer result = add.apply(2); // 返回 3
String answer = concat.apply("hi"); // 返回 "hi1"
Integer total = sum.apply(1, 2); // 返回 3
String name = getName.apply(); // 返回 "Carl"
結(jié)束語(yǔ):
之前一直用 C#、Objective-C、Swift 和 Python,因?yàn)榻衲暄芯可A段的課程以 Java 語(yǔ)言為主,所以開(kāi)始了解一下 Java。
感興趣的朋友歡迎關(guān)注本博客,也歡迎大家留言討論。
參考資料:
- Beginning Java objects by Jacquie Barker
- Java SE 8: Lambda Quick Start
- The big change in Java SE 8
- Functional Programming with Java 8 Functions
