Why does the method link create java.lang.BootstrapMethodError

I used to think of references to the java method as syntactic sugar, which was introduced as an addition to lambda expressions. But apparently this is not so.

In the example below, a method reference, unlike a lambda expression, throws an error. Can anyone explain this weird behavior?

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

Result:

{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

I ran the example in the following versions of java:
1.8.0_101-b13
1.8.0_131-B11

+6
source share

All Articles