13

运行下面的代码会导致错误消息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 中的双括号初始化(匿名内部类)允许代码按预期运行,为什么?以下作品:

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

编译器错误?毕竟是抢先体验版……

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

4

3 回答 3

7

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

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,异常的原因将包含其类型。例如:

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 错误。看来,问题出在加载的类堆栈上。它出现在 combine with 方法中,Java用于翻译lambda表达式(http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html) - 它在顶级类中生成合成方法。似乎,当在lambda堆栈中引入匿名类时,它会被破坏。可以使用提到的解决方法修复它。

于 2013-01-27T09:43:00.543 回答
2

编译器错误?毕竟是抢先体验版……

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

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

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

于 2013-01-27T00:44:34.180 回答
1

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

于 2014-01-18T16:28:41.157 回答