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

2022-09-04 22:12:31

运行以下代码会导致出现错误消息 。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 下载,否则此操作不会编译。


答案 1

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

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 typeReason: 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'

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

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

你怎么看?这解决了问题!一切开始都很好。甚至,如果我们要更改为 .检查这个!return A();return new A() {};


我的结论是,这是真正的JVM错误。似乎问题在于加载的类堆栈。它与方法结合使用,方法用于翻译表达式(http://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html) - 它在顶级内部产生合成方法。似乎,当在堆栈中引入匿名类时,就会变得破碎。可以使用提到的解决方法修复它。Javalambdalambda


答案 2

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

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

(看起来 JVM 报告了一个类型安全问题,编译器和/或字节码验证器在类加载时应该检测到这个问题。

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


推荐