→ pttworld: C_AND_CPP板至底文有一卡車貼程式碼網站 08/21 16:18
→ ssccg: Java8的這些新增功能是設計在與舊有type相容的原則上,提供 08/21 18:33
→ ssccg: function type寫法的支援,所以才用了functional interface 08/21 18:33
→ ssccg: 這個其實只是interface,不是新創一種function type的做法 08/21 18:35
→ ssccg: 好處就是讓舊有的API有可能無痛升級 08/21 18:37
感謝ss大,在看 lambda 前有看到 why lambda 的文章
該文舉了一個 filter apple 的例子,若新增需求,要一直新增或修改方法
透過設計的方式,有點像是用了 strategy pattern 來處理
然後使用 anonymous class 去解決,這是在 lambda 之前
然後 lambda 可以寫出更簡潔,更短的程式碼
是的,我看好像大部份介紹 lambda 提到的好處都是這樣
但是在後續的 Stream 會提到,並行處理,多執行緒處理等
換言之,導入 lambda 應該也是為了解決某些效能上的問題
不過現在頭痛的就是,java.util.function 是有定義好一些函式介面
但若我也定義了自己的函式介面,lambda 的 target type 是哪個不知道
雖說 java 8 設計的應該足以使用,不太需要自己定義函式介面了
然後看 Stream 時更亂了,一堆 lambda
然後我只能去看方法的參數到底是什麼型別
也就是目前如果要使用,我不知道如何快速的去應用這些 API
→ ssccg: lambda expression和method reference都可以evaluate成 08/21 18:38
→ ssccg: functional interface instance,但定義還是不一樣 08/21 18:39
→ ssccg: JLS在這兩種expression的type定義,前者在需要void回傳時 08/21 18:48
→ ssccg: lambda必須是statement或void-compatible block 08/21 18:51
→ ssccg: 但後者在需要void的時候,不管reference method的回傳type 08/21 18:54
→ ssccg: 理由大概也是讓舊有method能盡量無痛拿來reference 08/21 18:55
→ ssccg: 但是lambda expression是全新的所以適合較嚴格的限制 08/21 18:59
所以答案在 Java Language Specification 有提到
感謝ss大的說明 :)
→ ssccg: target type是看用在什麼地方,那個地方需要什麼type就會是 08/21 19:32
→ ssccg: 什麼type,因為目的就是模擬function type而不管是哪個 08/21 19:33
→ ssccg: interface type 08/21 19:34
→ ssccg: 在function type的概念上,API參數宣告成Consumer<String> 08/21 19:37
→ ssccg: 是代表需要一個String → void,是不是Consumer不重要 08/21 19:37
我現在要用 lambda 都必須先看 target type 的 function descriptor
例如 Predicate<T> 的 abstract method 為 boolean test(T t);
所以 function descriptor 是 T -> boolean
但是後面提到的,是不是 Consumer 不重要,這我看不懂
List<Dish> menuList = ...................
Stream<Dish> dishes = menuList.stream();
dishes.filter(d -> d.getCalories() < 400);
但我不能這樣寫啊
@FunctionalInterface
interface Gg {
boolean gg(Dish d);
}
Gg gg = d -> true;
dishes.filter(gg);
當然,這個例子蠻白痴的,我要用 API 本來就要知道他吃什麼參數
所以我不懂ss大說的,是不是 Consumer 不重要,是什麼意思?
或者是,我的腦袋根本還不知道 functional programming 的意思?
→ ssccg: 以你的例子來說,假設有個method是void test(Gg gg) 08/21 22:02
→ ssccg: 可以 dishes.filter(d -> d.getCalories() < 400); 08/21 22:02
→ ssccg: 也可以 test(d -> d.getCalories() < 400); 08/21 22:03
→ ssccg: d -> d.getCalories() < 400這個lambda "expression"本身是 08/21 22:03
→ ssccg: 沒有固定是哪個Interface type,是看用在哪就是哪個type 08/21 22:04
→ ssccg: 你下面的例子不行是因為d -> true這個lambda expression是 08/21 22:05
→ ssccg: 用在一個assignment statement要求type是Gg這個Interface 08/21 22:05
→ ssccg: 不是因為filter()不能接受d -> true 08/21 22:06
→ ssccg: 在API參數中用FunctionalInterface是描述需要的function而 08/21 22:07
→ ssccg: 不是需要的type,這是functional programming的精神 08/21 22:08
→ ssccg: 雖然受限FunctionalInterface實作,先把lambda expression 08/21 22:10
→ ssccg: 決定成某個Interface後就不能再變了,但平常寫程式lambda 08/21 22:11
→ ssccg: expression通常是直接用在method invoke的參數 08/21 22:12
以 Stream<T> 的 filter(Predicate<? super T> predicate)
因為 Predicate 的 function descriptor 是 T -> boolean
所以我在使用 filter() 時
d -> d.getCalories() < 400 也可以
d -> d.getType == Dish.Type.MEAT 也可以
d -> true 也可以
它們都符合 T -> boolean
使用 interface 就是讓我們注意在邏輯的實做就好
而不是想著要把它們歸屬於某個 type (某個 class)
就像我宣告了一個 Gg 的 functional interface
它的 functional descriptor 和 Predicate 一樣
但是我的思維是,用 Gg 解決某一個需求
下次遇到另一個需求,又宣告另一個 Yy 來解另一個需求
雖然程式是在用 lambda expression
但思維和原本的,遇到一個需求就增加一個 method 沒兩樣
也就是說 Predicate<T> 允許各種符合 function descriptor 的實作
我只要關注在,我的實做邏輯是什麼
然後用 lambda expression 丟進去就對了
這種理解不知道是否正確?
或是簡單說,我的 design pattern 的功力太弱
思維總是不夠抽象,總是對 concreat class 寫程式這樣對吧?
還是要感謝ssccg大的解說就是了 :)
※ 編輯: jtorngl (114.37.155.168 臺灣), 08/21/2019 22:54:45