Rei*_*ica 10 java lambda java-8
在交集类型中将方法引用应用于第二种类型时,我遇到了一个非常奇怪的问题.这是一个最小的测试用例:
class LambdaTest {
interface A {}
interface B {
B doIt();
}
static class AB implements A, B {
public B doIt() {
return this;
}
}
static <E extends A & B> void run(E e) {
Collections.singleton(e).stream().map(B::doIt);
}
public static void main(String[] args) {
run(new AB());
}
}
Run Code Online (Sandbox Code Playgroud)
此代码编译但run在运行时失败并出现错误:
java.lang.invoke.LambdaConversionException:无效的接收器类型接口LambdaTest $ A; 不是实现类型接口LambdaTest $ B的子类型
显式指定lambda的类型时甚至会发生此问题:
static <E extends A & B> void run(E e) {
final Function<E, B> doIt = B::doIt;
Collections.singleton(e).stream().map(doIt);
}
Run Code Online (Sandbox Code Playgroud)
显然,lambda预计将特别采用交叉口中的第一种类型而不是第二种类型.果然,更改方法签名run如下所示会使错误消失:
static <E extends B & A> void run(E e) {
Run Code Online (Sandbox Code Playgroud)
有趣的是,一些其他微小的变化也修复了错误.调用Object中的方法是有效的,大概是因为任何A也必须具有该方法:
Collections.singleton(e).stream().map(B::toString);
Run Code Online (Sandbox Code Playgroud)
此外,拉出功能参考run修复错误:
static <E extends A & B> void run(E e, Function<B, ?> f) {
Collections.singleton(e).stream().map(f);
}
public static void main(String[] args) {
run(new AB(), B::doIt);
}
Run Code Online (Sandbox Code Playgroud)
最后,将方法引用转换为常规lambda可以解决问题:
Collections.singleton(e).stream().map(x -> x.doIt());
Run Code Online (Sandbox Code Playgroud)
因此,似乎存在特定于方法引用的问题.编译器允许任何对交集类型有效的方法引用.但是,实现假定方法引用将采用第一种类型的交集A,即使明确指定了lambda的类型.然后,实现检查该方法是否在类型上可用A,如果不可用,则失败.
我的分析是否正确?这种行为是故意还是错误?
| 归档时间: |
|
| 查看次数: |
93 次 |
| 最近记录: |