簡體   English   中英

在官方Java教程中澄清Lambda表達式的工作方式

[英]Clarifying how Lambda expression works in the official Java tutorial

我已經一遍又一遍地閱讀了本教程 ,但我只是不了解方法6的最后一部分。

特別是這部分:

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

因此,以下方法調用與您在方法3中調用printPersons時相同:在本地類中指定搜索條件代碼以獲取符合選擇服務資格的成員:

printPersonsWithPredicate(
    roster,
    p -> p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25
);

因此,如果p是泛型類型,它怎么知道它是一個Person? 我只是不知道如何區分自己作為一個人,然后調用Person方法-getGender()和getAge()。 在這種情況下,p是否引用周圍類的類對象?


更新:

根據提供的答案,這正確嗎?

如下代碼:

interface CheckPerson {
    boolean test(Person p);
}

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

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

printPersons(roster, new CheckPersonEligibleForSelectiveService());

是相同的:

import java.util.function // import the Predicate<T> interface

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

printPersonsWithPredicate(
    roster,
    p -> p.getGender() == Person.Sex.MALE
        && p.getAge() >= 18
        && p.getAge() <= 25
);

因為:

  1. 謂詞接口已在java.util.function中定義
  2. 通過在方法參數中聲明謂詞為“人”:
    1. 我們隱式地實現了Person類型的謂詞,並且
    2. 調用具有通用類型T(或缺少通用類型T)的方法時,該類型被方法隱式推斷為Person

如果我錯了,請告訴我,以便我能更新我的理解。 我真的很想解決這個問題。

lambda表達式是Predicate<Person>#test主體的定義,該主體將Person作為參數。 我們知道這printPersonsWithPredicate是因為printPersonsWithPredicate被聲明為采用Predicate<Person> ,該lambda作為參數傳遞給它。

lambda的語法是->的左側是所定義方法的參數列表:

(Person p) -> p.getGender() == Person.Sex.MALE
    && p.getAge() >= 18
    && p.getAge() <= 25

但是,編譯器能夠確定lambda的奇異參數p必須是Person,因此可以將其省略。 因此,縮寫形式p -> ...

方法#4中顯示了一個與lambda幾乎等效的匿名類。

通常: 僅從相關功能接口的類型簽名中推斷出參數,包括對泛型參數的任何其他限制

在這種情況下,我們知道第二個參數是Predicate<T> 由於Predicate<T>是方法test(T t)的函數接口,因此我們知道p的類型為T (而不是Predicate<T> )。

而且由於TprintPersonsWithPredicate(List<Person> roster, Predicate<Person> tester)的簽名限制為Person ,因此 p的實際類型為Person


RE:UPDATE-答案既是“是”又是“否” :)。

“是”,通常可以以這種方式描述類型推斷的順序。

“否”,原因如下:

  • 在2.2中,我要說最好聲明該方法 T的類型限制Person 類型人就是所允許的“公共分母”。 例如:如果方法的簽名將包含:
    • Predicate<? extends JLabel> Predicate<? extends JLabel> -那么參數類型實際上是JLabel
    • Predicate<?> -那么參數類型實際上是Object
  • 最好聲明編譯器推斷出有關類型的某些信息,而不是由編譯器以外的其他“隱式定義”的信息。 您可能會認為它是無禮的選擇,但是此切換有兩個重要結果:
    • 這樣可以避免您陷入 “不是X代表N,而是Y”形式的陷阱
    • 非常特別地,由於編譯器能夠推斷出Predicate<Person>的類型是合法的,因此實際上無需創建實現功能接口的新匿名類 確實,在Java 8當前的JDK中, 就是這種情況 這是一篇說明細節的文章

僅解決UPDATE問題...

1)謂詞接口已在java.util.function中定義

正確

2)通過在方法參數中聲明謂詞為“人”:

不正確。

您實際上是將tester聲明為Predicate<Person> 您根本沒有在這里聲明Predicate Predicate是標准庫聲明的標准接口。

2a)我們正在隱式地實現帶有Person類型的謂詞

正確...有點。 您正在明確實現它。 並且這里所需的lambda的類型是由printPersonsWithPredicate的方法簽名顯式指定的。 具體來說,因為您聲明形式參數tester類型為Predicate<Person>

2b)調用具有通用類型T(或缺少通用類型T)的方法時,該類型被方法隱式推斷為Person

在這種情況下不行。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM