Java 中的函數(shù)式編程(Functional Programming):Lambda 初識(shí)

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)注本博客,也歡迎大家留言討論。

參考資料:

  1. Beginning Java objects by Jacquie Barker
  2. Java SE 8: Lambda Quick Start
  3. The big change in Java SE 8
  4. Functional Programming with Java 8 Functions
分享一張半個(gè)月前美國(guó)小鎮(zhèn)的雪景
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容