從Functional Interface跟匿名內部類別(Anonymous Inner Classes)了解使用Lambda表示式的好處

  • 建立一個functional interface 名為StringAnalyzer

主要是提供一個虛擬方法供類別實作該方法,未來在類別裡就必須實作出內容以分析目標字串(target)裡是否含有我們想要搜尋的字串(searhStr),有就回傳true

1

  • 接下來,建立一個ContainsAnalyzer實作該介面

主要是分析目標字串(target)裡是否含有(contains) 我們想要搜尋的字串(searhStr)

2

  • 最後,開發AnalyzerTestWithoutHelper類別

利用For迴圈把strList這個陣列裡的每個字串取出來,然後透過StringAnalyzer的實例(實例參考為contains)幫我們分析出哪些來源字串(currentStr)裡有找到搜尋的字串(searhStr),並將來源字串print出來。

3

然而,為了充份實作「封裝」的精神,我們應該進一步把屬於商業邏輯的程式碼變成一個方法(那就是原本的for迴圈那一段),範例如下:

其中searchArr()方法需要輸入3個參考,包括來源字串陣列, 想要搜尋的字串,和StringAnalyzer物件實例,最後藉由StringAnalyzer的實例會幫我們找出來源字串陣列裡符合分析結果的字串。

3_4

接下來我們就把AnalyzerTestWithoutHelper類別改寫成AnalyzerTestWithHelper類別,其中封裝for迴圈的searchArr()方法就是名符其實的Helper方法,程式範例如下:

4

上述的範例,我們是先建立一個ContainsAnalyzer類別,然而這個類別也許執行程式時只會用到一次,為了這一次就特地建立一個類別似乎有點不適合,所以我們也許可以考慮使用匿名內部類別(Anonymous Inner Classes),就可以將上述步驟(2),(3)合併在一起,範例如下:

5

完整的程式範例如下:

6

<接下來就進入另外一個主題了>

仔細比較AnalyzerTestWithHelpler類別(沒有使用匿名內部類別)跟AnalyzerTestWithoutAnonymousClass類別(有使用匿名內部類別)程式碼字元數,你會發現兩者差不了多少,意思就是使用匿名內部類別也不會使程式碼減少多少,反而讓人覺得寫法很複雜。

Java 8開始,我們可以使用Lambda表示式改善上述的例子以便能真正簡化程式碼的撰寫,使用Lambda表示式後,程式碼將變成這樣:

7

甚至變數名稱愈簡單,程式碼就更精簡,如下所示:

8

為何原本的匿名內部類別的語法可以改成用Lambda表示式的方式呈現,關鍵在於「編譯器如何善用已知的資訊」

我們就一步一步來分析。

首先,在呼叫searchArr()方法時,其實編譯器已經知道第三個參數要傳入的是StringAnalyzer的參考變數,所以程式碼跟本不用強調new StringAnalyzer(){},假設我們就刪除之:

9

再來因為StringAnalyzer是functional interface,唯一的方法的定義相當清楚(這就是為什麼我們的標題要強調「從Functional Interface…」),所以方法的「名稱」、「回傳型別」、「存取層級」等都已經知道,故public boolean analyze{}就可以不用寫出來,假設我們就刪除之:

10

進一步修改語法把「return」 關鍵字改成「->」同時移除行尾的「;」因為已經不是一個陳述式(statement)的結果了,變成是表示式(expression)了

11

因為已知道functional interface上唯一的方法的定義,所以二個參數的型別analyzer(String ?, String ?),也可以不用強調,假設我們就刪除之:

12

甚至變數名稱愈簡單,程式碼就更精簡,把target改為t,search改為s,就變成如下所呈現的最精簡的程式碼了,大公告成!!!

13

String類別除了提供contains()方法外,還有startsWith(), endsWIth(),所以未來我們可以很簡單的改變程式碼的邏輯,範例如下:

15

最後, Lambda表示式也可以用在變數,如此就可以定義一次,使用多次了,範例如下:

16

 

發表留言