问题描述
我在使用 jre1.8.0_66 运行的代码中遇到了这个奇怪的异常:
I'm getting this strange exception in code run using 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
这是什么意思?代码如下:
What's it mean? The code is as follows:
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()
.
The exception goes away if I change Fruit::getPickingMonth
to x -> x.getPickingMonth()
.
值得:如果我从任一类中删除 Serializable
,异常也会消失.但是,如果我向两个类添加另一个等效接口,则返回,例如Cloneable
或者一些自定义界面.
For what it's worth: The exception also goes away if I remove Serializable
from either class. But returns if I add another, equivalent interface to both classes, e.g. Cloneable
or some custom interface.
推荐答案
您遇到了在 this 中讨论过的相同编译器错误问题和那个问题.
只要涉及交集类型,并且您使用的方法引用使用的接收器类型不是第一个类型(第一个类型是类型擦除后将保留的类型),就会出现问题.
The problem occurs whenever an intersection type is involved and you are using a method reference using a receiver type other than the first one (the first type is the one that will remain after type erasure).
因此,当您将方法引用替换为 lambda 表达式时,您将不再受该错误的影响.如果您从类型中删除 Serializable
,则 Stream
的推断元素类型将是 Fruit
,即不是交集类型,并且再次问题不会发生.但是对于实现 Fruit
和 Serializable
的两种元素类型,编译器将推断元素类型 Object&Fruit&Serializable
并且原始类型将是Object
在使用接收器类型 Fruit
的方法引用时引发错误.您可以轻松解决此问题:
So when you replace the method reference with a lambda expression, you are not affected by the bug anymore. If you remove the Serializable
from the types instead, the inferred element type of the Stream
will be Fruit
, i.e. not an intersection type, and again the problem does not occur. But with the two element types implementing Fruit
and Serializable
, the compiler will infer the element type Object&Fruit&Serializable
and the raw type will be Object
which provokes the error when using a method reference with the receiver type Fruit
. You can easily work around this:
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::getPickingMonth
将实现类型 Function
而不是 Function
并且编译器错误没有实现.
The compiled code will be identical to your original, but the formal result type of the flatMap
operation will be Stream<Fruit>
, ignoring all other artifacts of the inferred intersection type. As a consequence the method reference Fruit::getPickingMonth
will implement the type Function<Fruit,Integer>
instead of Function<Object&Fruit&Serializable,Integer>
and the compiler bug does not materialize.
但请注意,您的代码过于复杂.你可以简单地使用
But note that your code is unnecessarily complicated. You can simply use
Stream.<Fruit>concat(apples.stream(), oranges.stream())
.map(Fruit::getPickingMonth) // no more exception on this line
.forEachOrdered(System.out::println);
达到同样的目的.
这篇关于奇怪的异常“无效的接收器类型类 java.lang.Object;不是……的子类型"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!