lambda上的LambdaConversionException在交集类型中采用第二种类型

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,如果不可用,则失败.

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