深入淺出:Java函數式編程中蘭姆達(Lambda)的5種應用模式

一、引言

我們知道,java函數式編程是在JDK8中引入,其主要特性支持基礎函數接口、蘭姆達(lambda)表達式以及流化(Stream)處理工具類等。

其中,函數接口為lambda表達式提供支持,Stream為lambda應用提供實施舞臺和和應用場景。同時JDK8中,很多的特性或類庫接口等也基於函數式編程做了很多的升級和補充。這方面的具體內容,這裡暫且不表。這裡主要介紹下函數接口和蘭姆達表達式。

每個人對函數式編程的理解不盡相同。但其核心是:在思考問題時,使用不可變值和函數,函數對一個值進行處理,映射成另一個值。這句話有點抽象,不理解暫時略過。

再看看百度上的解釋是:函數式編程是種編程方式,它將電腦運算視為函數的計算。函數編程語言最重要的基礎是λ演算(lambda calculus),而且λ演算的函數可以接受函數當作輸入(參數)和輸出(返回值)。簡單說,"函數式編程"是一種"編程範式"(programming paradigm),也就是如何編寫程序的方法論。它屬於"結構化編程"的一種,主要思想是把運算過程儘量寫成一系列嵌套的函數調用。

那麼,這樣基本可以理解所謂“函數式編程”的意思了,也有稱為“閉包”或“仿函數對象”的。需要注意的是這裡一個關鍵的概念就是“表達式”。這正是支持函數式編程的Java中Lambda表達式出現的重要意圖。

在java中,支持蘭姆達表達式的另一要求就是函數接口。所謂函數接口,即是隻有一個抽象方法的接口,用作 Lambda 表達式的類型

因此,在java中的蘭姆達表達式,你可以認為是一個又一個方法的匿名內部類,只是,lambda的處理方式更豐富了。當然,這需要多加練習才能真正理解和掌握。

這裡,希望通過一系列的有關Java函數式編程的深入淺出的介紹和演示教程,使你能理解並實際應用java的函數式編程。

二、Lambda的五種應用模式

1、無參數蘭姆達表達式

無參lambda表達式,一般以下面的形式應用:

Runnable noArguments = () -> System.out.println("Hello World");

上述語句形式中所示的 Lambda 表達式不包含參數,使用空括號 () 表示沒有參數。該 Lambda 表達式實現了 Runnable 接口,該接口也只有一個 run 方法,沒有參數,且返回類型為 void 。

如果我們想輸出蘭姆達表達式的結果,可以如下編寫代碼:

深入淺出:Java函數式編程中蘭姆達(Lambda)的5種應用模式

2.一參蘭姆達表達式

一參Lambda表達式形式如下:

ActionListener oneArgument = event -> System.out.println("button clicked");

以上代碼的傳統模式如下:

深入淺出:Java函數式編程中蘭姆達(Lambda)的5種應用模式

上述代碼即為Swing編程中GUI的典型界面操作。

換一種表達方式的示例代碼如下:

深入淺出:Java函數式編程中蘭姆達(Lambda)的5種應用模式

3.代碼塊蘭姆達表達式

其應用模式示例代碼如下:

深入淺出:Java函數式編程中蘭姆達(Lambda)的5種應用模式

也就是說,Lambda 表達式的主體不僅可以是一個表達式,而且也可以是一段代碼塊,使用大括號( {} )將代碼塊括起來,如所示。該代碼塊和普通方法遵循的規則別無二致,可以用返回或拋出異常來退出。只有一行代碼的 Lambda 表達式也可使用大括號,用以明確 Lambda表達式從何處開始、到哪裡結束。

4. 多個參數的方法蘭姆達表達式

其應用模式代碼是示例如下:

深入淺出:Java函數式編程中蘭姆達(Lambda)的5種應用模式

Lambda 表達式也可以表示包含多個參數的方法,如上所示。這時就有必要思考怎樣去閱讀該 Lambda 表達式。這行代碼並不是將兩個數字相加,而是創建了一個函數,用來計算兩個數字相加的結果。變量 add 的類型是 BinaryOperator<Long> ,它不是兩個數字的和,而是將兩個數字相加的那行代碼。

BinaryOperator是JDK8提供的函數編程類,可以查看對應的API參考說明。這裡不贅述了。

5.顯示傳遞Lambda表達式參數

其應用模式代碼示例如下(可以自行實現代碼運行):

BinaryOperator<Long> addExplicit = (Long x, Long y) -> x + y;

到目前為止,所有 Lambda 表達式中的參數類型都是由編譯器推斷得出的。這當然不錯,但有時最好也可以顯式聲明參數類型,此時就需要使用小括號將參數括起來,多個參數的情況也是如此。如上所示。

三、補充說明

通過上述幾個表達式的示例可知道,Lambda 表達式的類型依賴於上下文環境,是由編譯器推斷出來的,也就是Lambda的目標類型(即目標類型是指 Lambda 表達式所在上下文環境的類型。比如,將 Lambda 表達式賦值給一個局部變量,或傳遞給一個方法作為參數,局部變量或方法參數的類型就是 Lambda 表達式的目標類型)。

另外,Lambda表達式中參數是引用值,而不是變量,就像匿名類中引用final類型的變量一樣。也就是說,蘭姆達表達式中的參數,必須是"既成事實上的final變量"。只是Java8中放寬了這個限制。既成事實上的 final 是指只能給該變量賦值一次。換句話說,Lambda 表達式引用的是值,而不是變量。

通過示例可以更好理解&ldquo;既成事實的final變量&rdquo;:

代碼清單-1

深入淺出:Java函數式編程中蘭姆達(Lambda)的5種應用模式

代碼清單-2

深入淺出:Java函數式編程中蘭姆達(Lambda)的5種應用模式

清單-1是name是"既成事實的final變量",可以正常運行;二清單-2不是,編譯會出錯。

深入淺出:Java函數式編程中蘭姆達(Lambda)的5種應用模式

相關推薦

推薦中...