1. 程式人生 > >Java™ 教程(Lambda表示式)

Java™ 教程(Lambda表示式)

Lambda表示式

匿名類的一個問題是,如果匿名類的實現非常簡單,例如只包含一個方法的介面,那麼匿名類的語法可能看起來不實用且不清楚,在這些情況下,你通常會嘗試將方法作為引數傳遞給另一個方法,例如當有人單擊按鈕時應採取的操作,Lambda表示式使你可以執行此操作,將方法視為方法引數,或將程式碼視為資料。

上一節匿名類向你展示瞭如何在不給它命名的情況下實現基類,雖然這通常比命名類更簡潔,但對於只有一個方法的類,即使是匿名類也似乎有點過多和繁瑣,Lambda表示式允許你更緊湊地表達單方法類的例項。

Lambda表示式的理想用例

假設你正在建立社交網路應用程式,你希望建立一項功能,使管理員能夠對滿足特定條件的社交網路應用程式成員執行任何型別的操作,例如傳送訊息,下表詳細描述了此用例:

欄位 描述
名稱 對選定的成員執行操作
主要角色 管理員
前提條件 管理員已登入系統
後置條件 僅對符合指定條件的成員執行操作
主要成功案例 1. 管理員指定要執行特定操作的成員的條件
2. 管理員指定要對這些選定成員執行的操作
3. 管理員選擇Submit按鈕
4. 系統查詢符合指定條件的所有成員
5. 系統對所有匹配成員執行指定的操作
擴充套件 管理員可以選擇在指定要執行的操作之前或選擇Submit按鈕之前預覽符合指定條件的成員
發生頻率 一天中很多次

假設此社交網路應用程式的成員由以下Person類表示:

public class Person {

    public enum Sex {
        MALE, FEMALE
    }

    String name;
    LocalDate birthday;
    Sex gender;
    String emailAddress;

    public int getAge() {
        // ...
    }

    public void printPerson() {
        // ...
    }
}

假設你的社交網路應用程式的成員儲存在List<Person>例項中。

本節首先介紹這種用例的簡單方法,它使用區域性和匿名類改進了這種方法,然後使用lambda表示式以高效和簡潔的方法完成,在示例RosterTest中找到本節中描述的程式碼摘錄。

方法1:建立搜尋匹配一個特徵的成員的方法

一種簡單的方法是建立幾種方法,每種方法都會搜尋與一個特徵匹配的成員,例如性別或年齡,以下方法列印超過指定年齡的成員:

public static void printPersonsOlderThan(List<Person> roster, int age) {
    for (Person p : roster) {
        if (p.getAge() >= age) {
            p.printPerson();
        }
    }
}

注意:List是有序集合,集合是將多個元素組合到一個單元中的物件,集合用於儲存、檢索、操作和傳遞聚合資料,有關集合的更多資訊,請參閱集合路徑。

這種方法可能會使你的應用程式變得脆弱,這是由於引入了更新(例如更新的資料型別)導致應用程式無法工作的可能性。假設你升級應用程式並更改Person類的結構,使其包含不同的成員變數,也許類使用不同的資料型別或演算法記錄和測量年齡,你必須重寫大量API以適應此更改,此外,這種方法是不必要的限制;例如,如果你想要列印年齡小於某個年齡的成員,該怎麼辦?

方法2:建立更多廣義搜尋方法

以下方法比printPersonsOlderThan更通用;它會在指定的年齡範圍內列印成員:

public static void printPersonsWithinAgeRange(
    List<Person> roster, int low, int high) {
    for (Person p : roster) {
        if (low <= p.getAge() && p.getAge() < high) {
            p.printPerson();
        }
    }
}

如果你想要列印指定性別的成員,或指定性別和年齡範圍的組合,該怎麼辦?如果你決定更改Person類並新增其他屬性(如關係狀態或地理位置),該怎麼辦?雖然此方法比printPersonsOlderThan更通用,但嘗試為每個可能的搜尋查詢建立單獨的方法仍然會導致程式碼脆弱,你可以改為分離指定要在其他類中搜索的條件的程式碼。

方法3:在區域性類中指定搜尋條件程式碼

以下方法列印與你指定的搜尋條件匹配的成員:

public static void printPersons(
    List<Person> roster, CheckPerson tester) {
    for (Person p : roster) {
        if (tester.test(p)) {
            p.printPerson();
        }
    }
}

此方法通過呼叫方法tester.test來檢查List引數名單中包含的每個Person例項是否滿足CheckPerson引數tester中指定的搜尋條件,如果方法tester.test返回true值,則在Person例項上呼叫方法printPersons

要指定搜尋條件,請實現CheckPerson介面:

interface CheckPerson {
    boolean test(Person p);
}

以下類通過指定方法test的實現來實現CheckPerson介面,這種方法篩選在美國有資格參加兵役的成員:如果Person引數為男性且年齡介於18和25之間,則返回true值:

class CheckPersonEligibleForSelectiveService implements CheckPerson {
    public boolean test(Person p) {
        return p.gender == Person.Sex.MALE &&
            p.getAge() >= 18 &&
            p.getAge() <= 25;
    }
}

要使用此類,你需要建立它的新例項並呼叫printPersons方法:

printPersons(
    roster, new CheckPersonEligibleForSelectiveService());