首先,我不知道如何得体地表达这个问题,所以这是我的建议。
假设我们有以下重载方法:
void execute(Callable<Void> callable) {
try {
callable.call();
} catch (Exception e) {
e.printStackTrace();
}
}
<T> T execute(Supplier<T> supplier) {
return supplier.get();
}
void execute(Runnable runnable) {
runnable.run();
}
离开这张桌子,我又问了一个问题
Supplier () -> x
Consumer x -> ()
BiConsumer x, y -> ()
Callable () -> x throws ex
Runnable () -> ()
Function x -> y
BiFunction x,y -> z
Predicate x -> boolean
UnaryOperator x1 -> x2
BinaryOperator x1,x2 -> x3
以下是我在当地得到的结果:
// Runnable -> expected as this is a plain void
execute(() -> System.out.println());
// Callable -> why is it not a Supplier? It does not throw any exceptions..
execute(() -> null);
// Supplier -> this returns an Object, but how is that different from returning null?
execute(() -> new Object());
// Callable -> because it can throw an exception, right?
execute(() -> {throw new Exception();});
编译器如何知道调用哪个方法?例如,它如何区分什么是可调用的
和什么是可运行的
?
除了()-
()-
Callable
比Supplier
更具体(已经有评论建议)。Java文档声明,如果可能,它会选择最具体的类型:
类型推断是Java编译器查看每个方法调用和相应声明的能力,以确定使调用适用的类型参数。推理算法确定参数的类型,以及(如果可用)分配或返回结果的类型。最后,推理算法试图找到适用于所有参数的最具体类型。
// Callable -> why is it not a Supplier? It does not throw any exceptions..
execute(() -> null);
这是因为都是可调用的
显示
execute(可调用
设m1为第一种方法,m2为第二种方法。其中m2具有类型参数P1。。。,让α1。。。,αp是推理变量,θ是代换[P1:=α1,…,Pp:=αp]。
让我们。。。,ek可以是相应调用的参数表达式。然后:
如果m1和m2通过严格或宽松的调用适用(§15.12.2.2,§15.12.2.3),那么让S1。。。,Sk是m1的形式参数类型,设T1。。。,Tk是θ应用于m2的形式参数类型的结果
[…]
因此,
m1
是execute(可调用的)
现在只引用与问题相关的部分:
确定m1是否比m2更具体的过程如下:
>
首先,按照§18.1.3中的规定,从P1,..., Pp的声明边界构造初始约束集B。
第二,我(1)≤ 我≤ k) ,将生成一组约束公式或边界。
否则,Ti是功能接口的参数化,即必须确定Si是否满足以下五个条件:
[...]
如果所有五个条件都为真,则生成以下约束公式或界(其中U1... Uk和R1是Si捕获的函数类型的参数类型和返回类型,V1... Vk和R2是Ti函数类型的参数类型和返回类型):
如果ei是显式类型的lambda表达式:
- […]
- 否则,èR1
请注意,没有参数的lambda是显式类型的lambda。
将此应用回您的问题,R1
是Void
,R2
是对象
,约束是èR1
最后:
第四,生成的边界和约束公式被缩减并与B合并,以生成一个边界集B'。
如果B'不包含界假,并且B'中所有推理变量的解析成功,那么m1比m2更具体。
由于约束无效
// Supplier -> this returns an Object, but how is that different from returning null?
execute(() -> new Object());
在这种情况下,只有供应商
// Callable -> because it can throw an exception, right?
execute(() -> {throw new Exception();});
不完全是。抛出异常使可调用
对于表达式e,如果T不是S的子类型,且以下情况之一为真(其中U1…Uk和R1是S捕获的函数类型的参数类型和返回类型,V1…Vk和R2是T的函数类型的参数类型和返回类型),则函数接口类型S比函数接口类型T更具体:
如果e是一个显式类型的lambda表达式(§15.27.1),则以下情况之一为真:
- R2是无效的
基本上,对于显式类型的lambdas,任何非空
-返回函数接口类型都比空
-返回函数接口类型更具体。
我相信我已经找到了官方文件中描述的地方,尽管有点难读。
这里提到:
15.27.3. Lambda表达式的类型
请注意,虽然在严格的调用上下文中不允许装箱,但始终允许装箱lambda结果表达式——也就是说,结果表达式出现在赋值上下文中,而不管包含lambda表达式的上下文是什么。但是,如果显式类型的lambda表达式是重载方法的参数,则最具体的检查(§15.12.2.5)首选避免装箱或取消装箱lambda结果的方法签名。
然后这里(15.12.2.5)分析性地描述了如何选择最具体的方法。
根据这个例子
一个适用方法m1比另一个适用方法m2更具体,对于参数表达式e1。。。,ek,如果以下任何一项为真:
对于参数表达式e1,...,ek,m1被推断为比m2更具体
所以
// Callable -> why is it not a Supplier?
execute(() -> null); <-- Callable shall be picked from 2 options as M2 is generic and M1 is inferred to be more specific
void execute(Callable<Void> callable) { // <------ M1
try {
callable.call();
} catch (Exception e) {
e.printStackTrace();
}
}
<T> T execute(Supplier<T> supplier) { // <------ M2 is Generic
return supplier.get();
}
M1被推断为更具体的原因可以从这里描述的过程中追溯(18.5.4更具体的方法推断)
在JAVA8中,可以用lambda表达式替换内部类。 jvm怎么知道,这个lambda应该重写正确的方法?在上述示例中,它们是和。
我在超类中有一个重载方法的基本继承情况。 下面的类扩展了上面的类: main方法只是创建一个对象(静态和动态类型)并调用: 最后打印出来 看了这个,我想既然对象的静态和动态类型都是,它会调用Person中的重载方法,该方法将作为参数。由于我显然错了,我打开了一个调试器,假设类中的getWorkDetail(this)行中对“this”的引用一定已经变成了它的超级类。然而,这不是我发现的。 显然,在
本文向大家介绍Java8使用lambda表达式调用静态方法,包括了Java8使用lambda表达式调用静态方法的使用技巧和注意事项,需要的朋友参考一下 Java中的Lambda表达式允许您将功能作为参数传递给方法。您还可以使用lambda表达式调用现有的方法。 方法引用是简单的、易于阅读的lambda表达式,可以通过lambda表达式中的名称调用/引用现有的方法。可以使用方法引用引用类中定义的静态
在我的项目中,我使用Guava谓词和函数来使用和筛选和转换一些集合。 在这次迁移中,我需要将guava代码更改为Java8更改。所以,我所做的改变是这样的: 到... 由于,使用方法引用的方法还允许我调试转换过程: 多亏了answer,我注意到我的Eclipse没有显示它应该显示的内容,而peek()的使用有助于显示结果。
在我们的项目中,我们将迁移到Java8,并测试它的新特性。 在我的项目中,我使用Guava谓词和函数,使用和过滤和转换一些集合。 在这次迁移中,我需要更改例如guava代码到Java8的更改。所以,我正在做的改变是: 到... 使用guava调试代码非常符合要求,因为我可以调试每个转换过程,但我关心的是如何调试,例如。 由于,使用方法引用的方法还允许我调试转换过程: 由于回答,我注意到我的Ecli
本文向大家介绍Java中如何调试Lambda表达式,包括了Java中如何调试Lambda表达式的使用技巧和注意事项,需要的朋友参考一下 Lambda表达式由两部分组成,一个是参数,另一个是代码或表达式。 这两个部分由箭头运算符“->”分隔。 我们可以使用NetBeans,IntelliJ和Eclipse等不同的IDE来调试Java中的lambda表达式。 始终可以创建多行lambda表达式,并使用