2016-04-22 35 views
8

因此,假如我用一些隨機的過濾器上的流時,最簡單的方法就是直接輸入謂詞:使用謂詞或函數作爲Java流過濾器有什麼區別?

x.stream().filter(e -> e % 2 == 0) 

除了我可以簡單地做一個參考,並預先定義謂詞:

Predicate<Integer> isEven = e -> e % 2 == 0; 
... 
x.stream().filter(isEven) 

但我也用一個函數:

private static boolean isEven(Integer integer) { 
    return integer % 2 == 0; 
} 
... 
x.stream().filter(MyClass::isEven) 

據我所知,謂語當然是非常有限的,而功能可能有副作用等,但由於像Venkat Subramaniam這樣的人使用後者的解決方案,我真的想知道:這裏的主要區別是什麼?

回答

11

不!與方法參考相比,謂詞並不受限制!事實上,這些都是一樣的!

試想一下,在filter()函數簽名: filter(Predicate<? super T> predicate)

而且我們認爲您的例子:

x.stream().filter(e -> e % 2 == 0)

Predicate<Integer> isEven = e -> e % 2 == 0; 
... 
x.stream().filter(isEven) 

第一個是後者的只是一個內聯版本。

private static boolean isEven(Integer integer) { 
return integer % 2 == 0; 
} 
... 
x.stream().filter(MyClass::isEven) 

,在這裏你可以看到在行動Method References。 MR只是一個語法糖,允許您基於已有的函數定義Lambda表達式。

在一天結束時,所有這些表達式都變成Predicate函數接口的相同實現。

此外,您還可以使用右側塊語法執行你的Lambda表達式的副作用,但它一般不建議:

e -> { 
    //side effects here 
    return e % 2 == 0; 
} 
+0

我看到,如果沒有MR,我們只能定義關於其重用性的實際上有限的謂詞。所以這就產生了一個問題:更簡潔的寫作方式是什麼?使用MR,謂詞或實際陳述本身? – AdHominem

+1

@AdHominem它取決於你的上下文。如果你真的不想複用你的謂詞,那麼只需堅持一個簡單的lambda表達式,但是如果你要繼續使用它,我建議在一些utils類中創建一個靜態的Predicate實例,而不必創建一個方法本身 –

4

當它從視圖建立一個庫點看可重複使用的謂詞,返回一個布爾值的函數庫比靜態最終謂詞實例庫更多用途的謂詞集合。爲什麼?

考慮包含以下庫:

public static boolean isEven(int i) { return i -> i % 2 == 0; } 

public static final Predicate<Integer> IS_EVEN = i -> i % 2 == 0; 
  • 如果庫函數的命名很好,他們讀好。當久別重訪代碼更容易掃描filter(MyLib::isEven)filter(i -> i % 2 == 0)filter(MyLib::isEven)告訴你到底被調用了什麼,而filter(MyLib.IS_EVEN)
  • 如果你只是想打電話,而不是把它作爲一個謂語的庫函數,它更可讀。MyLib.isEven(i)掃描速度比MyLib.IS_EVEN.test(i)
  • 如果您需要使用IntPredicate代替Predicate<Integer>一個番石榴Predicate<Integer>,阿帕奇Collections4 Predicate<Integer>等,用庫函數好你只是繼續做MyLib::isEven。隨着static final Predicate<Integer>情況下,你將不得不做MyLib.IS_EVEN::test將其轉換(和你最終使用的方法參考反正)

同樣的道理適用於所有功能類型。寫功能。它們可以應用於與簡單方法引用相匹配的任何函數類型。

相關問題