lambda上的LambdaConversionException在交集类型

时间:2015-07-29 22:01:59

标签: java lambda java-8

在交集类型中将方法引用应用于 second 类型时,我遇到了一个非常奇怪的问题。这是一个最小的测试用例:

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中失败但错误:

  

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);
}

显然,lambda预计将特别采用交叉口中的第一种类型而不是第二种类型。果然,如下更改run的方法签名会使错误消失:

static <E extends B & A> void run(E e) {

有趣的是,一些其他的小改动也可以解决错误。调用Object中的方法是有效的,大概是因为任何A也必须有这个方法:

Collections.singleton(e).stream().map(B::toString);

此外,从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);
}

最后,将方法引用转换为常规lambda可以解决问题:

Collections.singleton(e).stream().map(x -> x.doIt());

所以似乎特别是方法引用存在问题。编译器允许任何对交集类型有效的方法引用。但是,实现假定方法引用将采用第一种类型的交集A,即使明确指定了lambda的类型。然后,实现检查该方法是否在类型A上可用,如果不可用,则失败。

我的分析是否正确?这种行为是故意还是错误?

0 个答案:

没有答案