1. 程式人生 > >Java 8 習慣用語,第 9 部分 級聯 lambda 表示式

Java 8 習慣用語,第 9 部分 級聯 lambda 表示式

原文地址:https://www.ibm.com/developerworks/cn/java/j-java8idioms9/index.html

Java 8 習慣用語,第 9 部分

級聯 lambda 表示式

可重用的函式有助於讓程式碼變得非常簡短,但是會不會過於簡短呢?

關於本系列

Java 8 是自 Java 語言誕生以來進行的一次最重大更新 — 包含了非常豐富的新功能,您可能想知道從何處開始著手瞭解它。在本系列中,作家兼教師 Venkat Subramaniam 提供了一種慣用的 Java 8 程式設計方法:這些簡短的探索會激發您反思您認為理所當然的 Java 約定,同時逐步將新技術和語法整合到您的程式中。

在函數語言程式設計中,函式既可以接收也可以返回其他函式。函式不再像傳統的面向物件程式設計中一樣,只是一個物件的工廠生成器,它也能夠建立和返回另一個函式。返回函式的函式可以變成級聯 lambda 表示式,特別值得注意的是程式碼非常簡短。儘管此語法初看起來可能非常陌生,但它有自己的用途。本文將幫助您認識級聯 lambda 表示式,理解它們的性質和在程式碼中的用途。

神祕的語法

您是否看到過類似這樣的程式碼段?

x -> y -> x > y

如果您很好奇“這到底是什麼意思?”,那麼您並不孤單。對於不熟悉使用 lambda 表示式程式設計的開發人員,此語法可能看起來像貨物正從快速行駛的卡車上一件件掉下來一樣。

幸運的是,我們不會經常看到它們,但理解如何建立級聯 lambda 表示式和如何在程式碼中理解它們會大大減少您的受挫感。

高階函式

在談論級聯 lambda 表示式之前,有必要首先理解如何建立它們。對此,我們需要回顧一下高階函式(已在本系列第 1 篇文章中介紹)和它們在函式分解中的作用,函式分解是一種將複雜流程分解為更小、更簡單的部分的方式。

首先,考慮區分高階函式與常規函式的規則:

常規函式

  • 可以接收物件
  • 可以建立物件
  • 可以返回物件

高階函式

  • 可以接收函式
  • 可以建立函式
  • 可以返回函式

開發人員將匿名函式或 lambda 表示式傳遞給高階函式,以讓程式碼簡短且富於表達。讓我們看看這些高階函式的兩個示例。

示例 1:一個接收函式的函式

在 Java™ 中,我們使用函式介面來引用 lambda 表示式和方法引用。下面這個函式接收一個物件和一個函式:

public static int totalSelectedValues(List<Integer> values, Predicate<Integer> selector) { return values.stream() .filter(selector) .reduce(0, Integer::sum);  }

totalSelectedValues 的第一個引數是集合物件,而第二個引數是 Predicate 函式介面。 因為引數型別是函式介面 (Predicate),所以我們現在可以將一個 lambda 表示式作為第二個引數傳遞給 totalSelectedValues。例如,如果我們想僅對一個 numbers 列表中的偶數值求和,可以呼叫 totalSelectedValues,如下所示:

totalSelectedValues(numbers, e -> e % 2 == 0);

假設我們現在在 Util 類中有一個名為 isEven 的 static 方法。在此情況下,我們可以使用 isEven 作為 totalSelectedValues 的引數,而不傳遞 lambda 表示式:

totalSelectedValues(numbers, Util::isEven);

作為規則,只要一個函式介面顯示為一個函式的引數的型別,您看到的就是一個高階函式。

示例 2:一個返回函式的函式

函式可以接收函式、lambda 表示式或方法引用作為引數。同樣地,函式也可以返回 lambda 表示式或方法引用。在此情況下,返回型別將是函式介面。

讓我們首先看一個建立並返回 Predicate 來驗證給定值是否為奇數的函式:

public static Predicate<Integer> createIsOdd() { Predicate<Integer> check = (Integer number) -> number % 2 != 0; return check; }

為了返回一個函式,我們必須提供一個函式介面作為返回型別。在本例中,我們的函式介面是 Predicate。儘管上述程式碼在語法上是正確的,但它可以更加簡短。 我們使用型別引用並刪除臨時變數來改進該程式碼:

public static Predicate<Integer> createIsOdd() { return number -> number % 2 != 0; }

這是使用的 createIsOdd 方法的一個示例:

Predicate<Integer> isOdd = createIsOdd(); isOdd.test(4);

請注意,在 isOdd 上呼叫 test 會返回 false。我們也可以在 isOdd 上使用更多值來呼叫 tes