簡體   English   中英

使用方法引用替換鏈式方法調用

[英]Replacing chained method call using method reference

“Java 8 Lambdas:實用功能編程”有一個在Stream API中使用peek方法的例子。 這段代碼打印名稱以“The”開頭的藝術家國籍:

Set<Nationality> nationalities = album.getMusician()
                                 .filter(artist -> artist.getName().startsWith("The"))
                                 .map(artist -> artist.getNationality())
                                 .peek(nation -> System.out.println(nation))
                                 .collect(Collectors.toList());

我想用方法引用重寫此代碼:

Set<Nationality> nationalities = album.getMusician()
                                 .filter(artist -> artist.getName().startsWith("The"))
                                 .map(Artist::getNationality)
                                 .peek(System.out::println)
                                 .collect(Collectors.toList());

是否有重寫filter(artist -> artist.getName().startsWith("The"))解決方案filter(artist -> artist.getName().startsWith("The"))

您需要創建一個單獨的方法,該方法接受一個Artist並返回一個布爾值:

private boolean nameStartsWithThe(Artist a) {
    return a.getName().startsWith("The");
}

Set<Nationality> nationalities = album.getMusician()
                                 .filter(this::nameStartsWithThe)

或使用靜態方法:

private static boolean nameStartsWithThe(Artist a) {
    return a.getName().startsWith("The");
}

Set<Nationality> nationalities = album.getMusician()
                                 .filter(MyClass::nameStartsWithThe)

你需要一些組成這兩種方法的東西。 有一些組合方法的方法( IntUnaryOperatorcomposeandThen方法可以將兩個IntUnaryOperator組合成一個新的IntUnaryOperator )。 但是我發現的那些似乎都專門用於某些類型的功能接口; 為每一對可能的功能接口類型定義compose方法會過於笨拙。

我確實得到了一些可以構成FunctionPredicate來獲得新Predicate

static <T,U> Predicate<T> functionPredicate(Function<T,U> func, Predicate<U> pred) {
    return obj -> pred.test(func.apply(obj));
}

也就是說,它可構成該上運行的謂詞T從一個函數,一個T並返回U ,和上操作的謂詞U 除了startsWith需要另一個參數之外,這幾乎適用於您的示例。 但這確實有效:

static boolean startsWithThe(String s) {
    return s.startsWith("The");
}

Predicate<Artist> pred = functionPredicate(Artist::getName, ThisClass::startsWithThe);

其中ThisClass是包含startsWithThe任何類。 這有效。 如果你想避免編寫一個新的方法(比如startsWithThe ),你可能會編寫一個“參數化謂詞”泛型方法,這樣你就可以寫一些像

Predicate<Artist> pred = functionPredicate(Artist::getName, parameterizedPredicate(String::startsWith, "The"));

但我沒試過。

所以似乎有可能提出一些讓你使用方法引用而不是lambdas的東西。 我懷疑它是否值得。 對我來說,方法參考只是某些種類的lambda的簡寫; 除非你能用一個簡單的方法引用做你想做的事情,我認為使用lambda是簡潔明了的,你不需要像我的functionPredicate方法那樣添加所有額外的rigmarole。 我已經看過幾個問題,比如“我怎么能用這個方法參考而不是lambda?”,老實說我不明白為什么。

無法用方法引用替換該行。


方法參考通過使用以下事實來工作:在整個lambda表達式中只使用一個對象,並且編譯器可以使用目標類型推斷它(引用無關緊要並且可以推斷類型)。

所以,

artist -> artist.getNationality()

被替換為

Artist::getNationality

這里Artist::getNationality方法與目標類型匹配,無需任何進一步的信息。


如果是artist -> artist.getName().startsWith("The") ,則lambda表達式中有兩個方法調用。 訂單,參數很重要,必須指定。

看起來好像應該推斷出artist引用,但是編譯器不會知道應該調用startsWith("The")方法的對象。

希望這可以幫助。

暫無
暫無

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

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