java 板


LINE

最近才开始看 lambda expression 直接看程式码都觉得很难看懂 有种必须以 compiler 的角度来看才知道 特别是 lambda 只要符合 function descriptor 都可编译 但是 target type 会是什麽,第一时间还真不知道是什麽 然後在练习 method reference 时,有一个地方一直无法理解 请看下面程式码部份的中文 另问,如果要问问题,有什麽比较好贴出程式码的地方吗? js 常看到 js fiddle import java.util.*; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; public class MethodReference { public static void main(String[] args) { List<String> strList = Arrays.asList("a", "b", "x"); /* == anonymous class == */ System.out.println("== anonymous class =="); strList.forEach(new Consumer<String>() { @Override public void accept(String s) { System.out.print(s + ","); } }); // a,b,x, /* * == lambda expression == * Consumer<String> abstract method: void accept(String s); * function descriptor: str -> void */ System.out.println("\n== lambda expression =="); strList.forEach( str -> System.out.print(str + ",") ); strList.forEach( str -> {} ); strList.forEach( str -> {return;} ); /* Error: incompatible types: bad return type in lambda expression */ // strList.forEach( str -> "[" + str + "]" ); 这里使用 lambda 时,回传值非 void 时会编译错误 我是用,因为 forEach() 要的是 Consumer 所以要符合 Consumer 的 function descriptor 去理解 /* == Class::staticMethod == */ System.out.println("\n== Class::staticMethod =="); strList.forEach(MethodReference::staticPrint); strList.forEach(MethodReference::xxx); /* compile success?? */ strList.forEach(MethodReference::yyy); 这里编译也成功,参数数目对了,但是方法回传值不为 void 那 lambda 不行,但是 method reference 却可以 是什麽原因呢? 因为 method 的 signature 不包括 return type ? /* Error: incompatible types: invalid method reference */ // strList.forEach(MethodReference::zzz); // strList.forEach(MethodReference::www); 这里也会编译错误,因为 Consumer 的 function descriptor 参数列表只允许一个引数传入 /* object::instanceMethod */ System.out.println("\n== object::instanceMethod =="); MethodReference ref = new MethodReference(); strList.forEach(ref::instancePrint); /**** Class::instanceMethod ****/ System.out.println("\n== Class::instanceMethod =="); strList.forEach(System.out::print); } private static void staticPrint(String s) { System.out.print(s + ","); } private void instancePrint(String s) { System.out.print(s + ","); } private static void xxx(String s) { } private static String yyy(String s) { return (s == null ? "" : s) + "..."; } private static void zzz() { } private static void www(String s1, String s2) { } } --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 114.37.155.168 (台湾)
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/java/M.1566369273.A.05B.html
1F:→ pttworld: C_AND_CPP板至底文有一卡车贴程式码网站 08/21 16:18
2F:→ ssccg: Java8的这些新增功能是设计在与旧有type相容的原则上,提供 08/21 18:33
3F:→ ssccg: function type写法的支援,所以才用了functional interface 08/21 18:33
4F:→ ssccg: 这个其实只是interface,不是新创一种function type的做法 08/21 18:35
5F:→ 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
6F:→ ssccg: lambda expression和method reference都可以evaluate成 08/21 18:38
7F:→ ssccg: functional interface instance,但定义还是不一样 08/21 18:39
8F:→ ssccg: JLS在这两种expression的type定义,前者在需要void回传时 08/21 18:48
9F:→ ssccg: lambda必须是statement或void-compatible block 08/21 18:51
10F:→ ssccg: 但後者在需要void的时候,不管reference method的回传type 08/21 18:54
11F:→ ssccg: 理由大概也是让旧有method能尽量无痛拿来reference 08/21 18:55
12F:→ ssccg: 但是lambda expression是全新的所以适合较严格的限制 08/21 18:59
所以答案在 Java Language Specification 有提到 感谢ss大的说明 :)
13F:→ ssccg: target type是看用在什麽地方,那个地方需要什麽type就会是 08/21 19:32
14F:→ ssccg: 什麽type,因为目的就是模拟function type而不管是哪个 08/21 19:33
15F:→ ssccg: interface type 08/21 19:34
16F:→ ssccg: 在function type的概念上,API参数宣告成Consumer<String> 08/21 19:37
17F:→ 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 的意思?
18F:→ ssccg: 以你的例子来说,假设有个method是void test(Gg gg) 08/21 22:02
19F:→ ssccg: 可以 dishes.filter(d -> d.getCalories() < 400); 08/21 22:02
20F:→ ssccg: 也可以 test(d -> d.getCalories() < 400); 08/21 22:03
21F:→ ssccg: d -> d.getCalories() < 400这个lambda "expression"本身是 08/21 22:03
22F:→ ssccg: 没有固定是哪个Interface type,是看用在哪就是哪个type 08/21 22:04
23F:→ ssccg: 你下面的例子不行是因为d -> true这个lambda expression是 08/21 22:05
24F:→ ssccg: 用在一个assignment statement要求type是Gg这个Interface 08/21 22:05
25F:→ ssccg: 不是因为filter()不能接受d -> true 08/21 22:06
26F:→ ssccg: 在API参数中用FunctionalInterface是描述需要的function而 08/21 22:07
27F:→ ssccg: 不是需要的type,这是functional programming的精神 08/21 22:08
28F:→ ssccg: 虽然受限FunctionalInterface实作,先把lambda expression 08/21 22:10
29F:→ ssccg: 决定成某个Interface後就不能再变了,但平常写程式lambda 08/21 22:11
30F:→ 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







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:iOS站内搜寻

TOP