操作数堆栈上的错误类型…使用jdk 8,带有匿名内部类的lambdas失败,为什么?

运行下面的代码会导致Bad type on operand stack的错误消息Bad type on operand stack

 public static void main(String args[]) { TransformService transformService = (inputs) -> { return new ArrayList(3) {{ add("one"); add("two"); add("three"); }}; }; Collection inputs = new HashSet(2) {{ add(5); add(7); }}; Collection results = transformService.transform(inputs); System.out.println(results.size()); } public interface TransformService { Collection transform(Collection inputs); } 

但是,删除lamda中的双括号初始化(匿名内部类)允许代码按预期运行,为什么? 以下作品:

 public class SecondLambda { public static void main(String args[]) { TransformService transformService = (inputs) -> { Collection results = new ArrayList(3); results.add("one"); results.add("two"); results.add("three"); return results; }; Collection inputs = new HashSet(2) {{ add(5); add(7); }}; Collection results = transformService.transform(inputs); System.out.println(results.size()); } public interface TransformService { Collection transform(Collection inputs); } } 

编译错误? 毕竟这是早期的访问版本……

(除非你有最新的jdk 8 lambda下载,否则不会编译。)

看来,这个问题不仅发生在lambda返回anonymous类型的情况下,而且即使在lambda构造了任何匿名类。 即:

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

这实际上导致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 ,exception的原因将包含其类型。 例如:

Type 'java/lang/Integer' (current frame, stack[0]) is not assignable to 'lambda/TestLambda'

这已经非常有趣了。 让我们将xxx参数的类型(实际上并未使用)更改为顶级类型,即TestLambda

 ... xxx(new TestLambda()); } private static void xxx(TestLambda x) { ... 

你觉得怎么样? 这解决了这个问题! 一切都开始好起来。 甚至,如果我们改变return A(); return new A() {}; 。 检查一下!


我的结论是,这是真正的JVM错误 。 看来,问题在于加载类的堆栈。 它与方法相结合, Java用于翻译lambda表达式( http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html ) – 它在顶级类中生成合成方法。 看来,当lambda堆栈中引入匿名类时会被破坏。 它可以使用上面提到的解决方法来修复。

编译错误? 毕竟这是早期的访问版本……

我会说任何提到操作数堆栈的错误消息很可能是由于编译器错误或JVM中的错误。 特别是如果你可以使用纯Java示例来获取它。

(看起来JVM正在报告编译器应该检测到的类型安全问题,和/或类加载时的字节码validation程序。)

通过推荐的Java 8错误频道报告。

与您的问题没有直接关系,但我强烈建议您不要以这种方式使用匿名类。 您只是为了向其添加两个值而创建一个全新的HashSet子类型。 这不仅会使系统膨胀(它永远留在内存中),它也会混淆JVM的JIT,因为它永远不会在呼叫站点看到HashSet ……它会看到你创建的许多子类型之一。