[问题] method reference

楼主: jtorngl (Pedrosa go!)   2019-08-21 14:34:30
最近才开始看 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) {
}
}
作者: pttworld (批踢踢世界)   2019-08-21 16:18:00
C_AND_CPP板至底文有一卡车贴程式码网站
作者: ssccg (23)   2019-08-21 18:33:00
Java8的这些新增功能是设计在与旧有type相容的原则上,提供function type写法的支援,所以才用了functional interface这个其实只是interface,不是新创一种function type的做法好处就是让旧有的API有可能无痛升级lambda expression和method reference都可以evaluate成functional interface instance,但定义还是不一样JLS在这两种expression的type定义,前者在需要void回传时lambda必须是statement或void-compatible block但后者在需要void的时候,不管reference method的回传type理由大概也是让旧有method能尽量无痛拿来reference但是lambda expression是全新的所以适合较严格的限制target type是看用在什么地方,那个地方需要什么type就会是什么type,因为目的就是模拟function type而不管是哪个interface type在function type的概念上,API参数宣告成Consumer<String>是代表需要一个String → void,是不是Consumer不重要以你的例子来说,假设有个method是void test(Gg gg)可以 dishes.filter(d -> d.getCalories() < 400);也可以 test(d -> d.getCalories() < 400);d -> d.getCalories() < 400这个lambda "expression"本身是没有固定是哪个Interface type,是看用在哪就是哪个type你下面的例子不行是因为d -> true这个lambda expression是用在一个assignment statement要求type是Gg这个Interface不是因为filter()不能接受d -> true在API参数中用FunctionalInterface是描述需要的function而不是需要的type,这是functional programming的精神虽然受限FunctionalInterface实作,先把lambda expression决定成某个Interface后就不能再变了,但平常写程式lambdaexpression通常是直接用在method invoke的参数

Links booklink

Contact Us: admin [ a t ] ucptt.com