问题描述
运行以下代码会导致错误消息操作数堆栈上的错误类型
。
Running the code below results in the error message Bad type on operand stack
.
public static void main(String args[]) {
TransformService transformService = (inputs) -> {
return new ArrayList<String>(3) {{
add("one");
add("two");
add("three");
}};
};
Collection<Integer> inputs = new HashSet<Integer>(2) {{
add(5);
add(7);
}};
Collection<String> results = transformService.transform(inputs);
System.out.println(results.size());
}
public interface TransformService {
Collection<String> transform(Collection<Integer> inputs);
}
然而,删除lamda中的双括号初始化(匿名内部类)允许代码按预期运行,为什么?以下工作原理:
However removing the double brace initialization (anonymous inner classes) within the lamda allows the code to run as expected, why ? The below works :
public class SecondLambda {
public static void main(String args[]) {
TransformService transformService = (inputs) -> {
Collection<String> results = new ArrayList<String>(3);
results.add("one");
results.add("two");
results.add("three");
return results;
};
Collection<Integer> inputs = new HashSet<Integer>(2) {{
add(5);
add(7);
}};
Collection<String> results = transformService.transform(inputs);
System.out.println(results.size());
}
public interface TransformService {
Collection<String> transform(Collection<Integer> inputs);
}
}
编译错误?毕竟它是早期的访问版本...
Compiler bug ? It is the early access version after all ...
(除非你有最新的。)
推荐答案
看来,该问题不仅发生在 lambda
返回匿名
类型的情况下,但即使在<$内部构造任何匿名类C $ C>拉姆达。即:
It seems, that problem occurs not only in case when lambda
returns anonymous
type, but even if any anonymous class is constructed inside lambda
. I.e.:
public class TestLambda {
public static void main(String[] args) {
xxx();
}
static void xxx() {
Functional1 f = () -> {
Object o = new Object() { };
return new A();
};
}
static class A { }
static interface Functional1 { A func(); }
}
这实际上导致线程中的异常main java.lang.VerifyError:错误的局部变量类型
(...)原因:类型top(当前帧,locals [0])不能分配给引用类型
。
This actually leads to Exception in thread "main" java.lang.VerifyError: Bad local variable type
(...) Reason: Type top (current frame, locals[0]) is not assignable to reference type
.
进一步调查显示,如果我们将参数引入方法 xxx
,原因对于异常将包含其类型。例如:
Further investigation shows, that if we will introduce parameter into method xxx
, the reason for an exception will contains its type. E.g.:
类型'java / lang / Integer'(当前帧,堆栈[0])不能分配给'lambda / TestLambda'
这已经非常有趣了。让我们将 xxx
参数(实际上并未使用)更改为 top 类的类型,即 TestLambda
:
And this is already very interesting. Let's change type of xxx
parameter (which is not actually used) to type of top class, i.e. TestLambda
:
...
xxx(new TestLambda());
}
private static void xxx(TestLambda x) {
...
你觉得怎么样? 这解决了问题!一切都开始运作良好。甚至,如果我们将更改为A();
返回,则返回新的A(){};
。检查一下!
And what do you think? This fixes the problem! Everything begin work well. Even, if we will change return A();
to return new A() {};
. Check this!
我的结论是这是真正的 JVM bug 。看来,问题在于加载类的堆栈。它与方法结合使用, Java
用于翻译 lambda
表达式( - 它产生了顶级类中的合成方法。看来,当在 lambda
中引入匿名类时,堆栈就会被破坏。它可以使用上面提到的解决方法来修复。
My conclusion is that this is real JVM bug. It seems, that the problem is with stack of loaded classes. It occurs in combine with method, which Java
uses for translating lambda
expressions (http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html) - it produces synthetic methods inside top class. It seems, that when anonymous classes are introduced in lambda
stack becomes broken. It could be fixed using mentioned workaround.
这篇关于操作数堆栈上的错误类型...使用jdk 8,带有匿名内部类的lambdas失败,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!