學習 Java8 函數式編程 (二)

和 Lambda 表達式 Say Hello

如果用一大段枯燥的文字去解釋一個我們并不熟悉的概念,我覺得和看天書并無區別。我之所以選擇學編程,就是因為沒有什么是寫段代碼不能搞定的。那么廢話少說,大家先看看清單一中的代碼。

清單一

public class Calculater {

    public static void main(String[] args) {
        final int a = 1, b = 2;
        int result = add(new IIntegerMath() {
            @Override
            public int operation() {
                return a + b;
            }
        });

        System.out.println(result);
    }

    public static int add(IIntegerMath iIntegerMath) {
        return iIntegerMath.operation();
    }

}

interface IIntegerMath {

    int operation();

}

看完清單一中的代碼,估計有人要說我了,因為這段代碼在上一篇博客中已經出現過了。但這又何妨,通過一段簡單的代碼,我們可以挖掘很多知識。在清單一代碼的 main 函數中,我調用了 add 函數,并使用了一個匿名內部類作為 add 函數的參數。匿名內部類被設計的目的之一就是,方便程序員將代碼作為數據傳遞。

現在問題來了,大家有沒有覺得這樣的代碼太過于冗余了。我們明明只需要 a + b 這一條語句,卻附加了很多其他的代碼(命令式代碼)。可能由于大家已經習慣了這樣的寫法,但 Java8 讓我們可以用更加簡單的代碼實現相同的功能。那么,我們一起來看清單二中用** Java8** 實現地與清單一功能相同的代碼。

清單二

public class Calculater {

    public static void main(String[] args) {
        int a = 1, b = 2;
        int result = add(() -> a + b);

        System.out.println(result);
    }

    public static int add(IIntegerMath iIntegerMath) {
        return iIntegerMath.operation();
    }

}

interface IIntegerMath {

    int operation();

}

如果有人認為清單二中的代碼看著不爽,那么我建議他可以去泡個澡,然后剪個頭發。其實清單二中的代碼我已經在上篇博客中展示了,但我并沒有解釋 () -> a + b 是幾個意思。

我現在給大家分析下 () -> a + b ,其實這段代碼就是一個 Lambda 表達式,也可以理解為一個函數。-> 將參數和 Lambda 表達式的主體分割開了,-> 的左邊是參數所在的位置,() 表示無參數;-> 右邊的代碼是 Lambda 表達式的主體。

即使我們知道了 add 函數中那段代碼是什么意思,我認為有些人對于在 add 函數中直接傳入一個 Lambda 表達式還是難以理解。那么現在我用另一種方式重寫清單二中 main 函數中的代碼,請看清單三。

清單三

public static void main(String[] args) {
        int a = 1, b = 2;
        IIntegerMath integerMath = () -> a + b;
        int result = add(integerMath);

        System.out.println(result);
}

我相信清單三中的代碼對于大家來說都很熟悉。當你無法理解使用 Lambda 表達式作為函數參數的用法,你們就將 Lambda 表達式理解為一個對象的引用,雖然按理來說我們不能這么來理解。

Lambda 表達式的多種形式

不帶參數的 Lambda 表達式

清單四

public class LambdaLearn {
    public static void main(String[] args) {
        INoArguments noArguments =
            () -> System.out.println("no argument");
    }
}

interface INoArguments {
    void printOperation();
}

清單四中展示了一個不帶參數的 Lambda 表達式,在 -> 的左邊使用空括號 () 代表沒有參數

帶一個參數的Lambda表達式

清單五

public class LambdaLearn {
    public static void main(String[] args) {
        IOneArguments<Integer> oneArguments =
            (a) -> a > 0;
    }
}

interface IOneArguments<T> {
    boolean assertOneNum(T argument);
}

清單五展示了一個只帶一個參數的 Lambda 表達式,因為只有一個參數,所以參數可以用括號包裹起來,也可以不用。

帶多個參數的 Lambda 表達式

清單六

public class LambdaLearn {
    public static void main(String[] args) {
        IMultiArguments<Integer> multiArguments =
            (a, b) -> a + b;
    }
}

interface IMultiArguments<T> {
    T addOperation(T a, T b);
}

清單六中展示了一個帶多個參數的 Lambda 表達式。因為有多個參數,所以需要用括號將多個參數包裹起來。

注意:我不能用慣性思維去閱讀清單六中 Lambda 表達式。該 Lambda 表達式并不是將兩個數字相加,而是創建了一個函數,用來計算兩個數字相加的結果。變量 multiIArguments
的類型是 IMultiArguments<Integer>,它不是兩個數字相加的和,而是將兩個數字相加的那行代碼。

主體用被{}包裹的 Lambda 表達式

清單七

public class LambdaLearn {
    public static void main(String[] args) {
          INoArguments multiStatement = ()  ->  {
            System.out.println("this is the first code");
            System.out.println("this is the second code");
        };
        
        INoArguments oneStatement = ()  ->  {
            System.out.println("only one code");
        };
    }
}


interface INoArguments {
    void printOperation();
}

清單七中展示了,如果 Lambda 表達式的主體有多行代碼,那么就需要將多行代碼用**中括號 {} **包裹。其實當 Lambda 表達式的主體只有一行代碼的時候,大家可以根據自己的習慣決定是否使用中括號。

通過 Lambda 表達式來看 Java8

既成事實地final變量

在我們學 Java 基礎的時候,我們就知道匿名內部類只能引用外部的 final 變量。但我們卻發現,被 Lambda 表達式引用的外部變量并沒有被 final 修飾。如清單八中的代碼所示,被 Lambda 表達式引用的外部變量 a 和 b 并誒有被 final 修飾,這是因為 Java8 為我們省去了一些操作,這樣代碼看上去會更加干凈舒服。雖然 a 和 b 沒有被顯示地被 final 修飾,但它們依然是事實上的 final 變量。你們可以根據自己的喜好,選擇性地給被 Lambda 表達式引用的外部變量加上 final 修飾符。

清單八

public static void main(String[] args) {
        int a = 1, b = 2;
        IIntegerMath integerMath = () -> a + b;
        int result = add(integerMath);

        System.out.println(result);
}

類型推斷

不知大家是否有注意,本文中使用的 Lambda 表達式都沒有為參數指明類型,這是因為 Java8 引入了比 Java7 更加強大的目標類型推斷。如清單九中的代碼所示, Lambda 表達式的參數 x 并沒有被指明類型,但 javac 會根據變量 atLeast 的類型 Predicate<Integer> 推斷出目標類型。在日常的開發中,請大家根據具體情況選擇是否給 Lambda 表達式的參數顯示地指明類型

清單九

Predicate<Integer> atLeast = x -> x > 5;

interface Predicate<Integer> {
    boolean test(T t);
}

彩蛋

其實我的微信里有關注很多技術公眾號,但真正喜歡并經常閱讀的卻寥寥無幾,其中劉欣大神的碼農翻身就是我非常喜歡的一個公眾號。劉欣大哥是一個有 15 年工作經驗的前 IBM 架構師,他是一個熱愛編程的資深碼農,他用心去寫好每一篇博客,他的每篇博客都是一個故事,他用一個個精彩短小的故事解釋有點枯燥的技術。下面是他公眾號的二維碼,請關注他,你們會收獲很多。

碼農翻身
碼農翻身

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容