java - 奇怪的异常 "Invalid receiver type class java.lang.Object; not a subtype of ..."

标签 java java-8 java-stream

我在使用 jre1.8.0_66 运行的代码中遇到了这个奇怪的异常:

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
Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class java.lang.Object; not a subtype of implementation type interface Fruit
    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)
    ... 3 more

这是什么意思?代码如下:

public static interface Fruit {

    int getPickingMonth();
}

public static class Apple implements Fruit, Serializable {

    @Override
    public int getPickingMonth() {
        return 11;
    }
}

public static class Orange implements Fruit, Serializable {

    @Override
    public int getPickingMonth() {
        return 2;
    }
}

public static void main(String[] args) {

    List<Apple> apples = Arrays.asList(new Apple());
    List<Orange> oranges = Arrays.asList(new Orange());

    Stream.of(apples.stream(), oranges.stream())
            .flatMap(Function.identity())
            .map(Fruit::getPickingMonth)  // exception occurs on this line
            .forEachOrdered(System.out::println);
}

如果我将 Fruit::getPickingMonth 更改为 x -> x.getPickingMonth(),异常就会消失。

它的值(value):如果我从任一类中删除 Serializable,异常也会消失。但是,如果我向两个类添加另一个等效接口(interface),则返回,例如Cloneable 或一些自定义界面。

最佳答案

您遇到了在 this question 中讨论过的相同编译器错误和 that question .

每当涉及交集类型并且您使用的方法引用使用的接收器类型不是第一个类型(第一个类型是类型删除后将保留的类型)时,就会出现此问题。

因此,当您将方法引用替换为 lambda 表达式时,您将不再受到该错误的影响。如果删除 Serializable相反,从类型中推断出 Stream 的元素类型将是 Fruit ,即不是交集类型,问题也不会发生。但是这两种元素类型实现了 FruitSerializable ,编译器将推断元素类型 Object&Fruit&Serializable原始类型将是 Object在使用接收者类型为 Fruit 的方法引用时引发错误.您可以轻松解决此问题:

Stream.of(apples.stream(), oranges.stream())
        .<Fruit>flatMap(Function.identity())
        .map(Fruit::getPickingMonth) // no more exception on this line
        .forEachOrdered(System.out::println);

编译后的代码将与您的原始代码相同,但 flatMap 的正式结果类型操作将是Stream<Fruit> ,忽略推断的交集类型的所有其他工件。因此,方法引用 Fruit::getPickingMonth将实现类型 Function<Fruit,Integer>而不是 Function<Object&Fruit&Serializable,Integer>并且编译器错误没有实现。

但请注意,您的代码不必要地复杂。你可以简单地使用

Stream.<Fruit>concat(apples.stream(), oranges.stream())
        .map(Fruit::getPickingMonth) // no more exception on this line
        .forEachOrdered(System.out::println);

实现相同。

关于java - 奇怪的异常 "Invalid receiver type class java.lang.Object; not a subtype of ...",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33929304/

相关文章:

java - Android 压缩纹理加载(缺少 GL 扩展)

java - 有人可以向我解释为什么 L(长)必须在那里吗?

Java 8 Stream 获取最小值

java - 克服 equals() : Stream<String> seems to be unrelated to String 不太可能的参数类型的优雅方法

Java 8 map 流

java - 简单来说,什么是工厂?

java - 调用函数时数组为空(java)

Java 内存泄漏 - jmap 不显示类,但 jstat 显示

java - 连接关闭后结果集被清除。 SQLite

java - 在 wicket7 中填写表格并输入 key 提交