为什么方法引用会产生java.lang.BootstrapMethodError

Art*_*rov 7 java generics lambda java-stream method-reference

我曾经把java方法引用看作是一个语法糖,它是作为lambda表达式的一个补充而引入的.但显然事实并非如此.

在下面的示例中,与lambda表达式不同,方法引用会产生错误.
有人可以解释一下奇怪的行为吗?

import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Main {

    public static void main(String[] args) {
        System.out.println(getMapUsingLanmdaApproach(MyEnum.class)); // works as expected: {1=A, 2=B}
        System.out.println(getMapUsingMethodReferenceApproach(MyEnum.class));   // throws java.lang.BootstrapMethodError
    }

    static <K, V extends Enum<?> & HasProperty<K>> Map<K, V> getMapUsingLanmdaApproach(Class<V> aClass) {
        return Stream.of(aClass.getEnumConstants())
                .collect(Collectors.toMap(e -> e.getProperty(), Function.identity()));
    }

    static <K, V extends Enum<?> & HasProperty<K>> Map<K, V> getMapUsingMethodReferenceApproach(Class<V> aClass) {
        return Stream.of(aClass.getEnumConstants())
                .collect(Collectors.toMap(HasProperty::getProperty, Function.identity()));
    }
}

enum MyEnum implements HasProperty<Integer> {
    A(1),
    B(2);

    private final Integer property;

    MyEnum(Integer property) {
        this.property = property;
    }

    @Override
    public Integer getProperty() {
        return property;
    }
}

@FunctionalInterface
interface HasProperty<K> {
    K getProperty();
}
Run Code Online (Sandbox Code Playgroud)

结果:

{1=A, 2=B}
Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception
    at java.lang.invoke.CallSite.makeSite(CallSite.java:341)
    at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
    at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
    at Main.getMapUsingMethodReferenceApproach(Main.java:19)
    at Main.main(Main.java:10)
Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class java.lang.Enum; not a subtype of implementation type interface HasProperty
    at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233)
    at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
    at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
    ... 4 more
Run Code Online (Sandbox Code Playgroud)

我在下一个java版本上运行了这个例子:
1.8.0_101-b13
1.8.0_131-b11