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ラムダダウンロードがない限り、これはコンパイルされません。)

4

3 に答える 3

7

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、例外の理由にはそのタイプが含まれることがわかります。例えば:

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これは、式の変換に使用するメソッドlambdahttp://cr.openjdk.java.net/~briangoetz/lambda/lambda-translation.html )と組み合わせて発生します。これは、トップクラス内に合成メソッドを生成します。匿名クラスがlambdaスタックに導入されると壊れてしまうようです。上記の回避策を使用して修正できます。

于 2013-01-27T09:43:00.543 に答える
2

コンパイラのバグ?やっぱり早期アクセス版です...

オペランドスタックに言及しているエラーメッセージは、コンパイラのバグまたはJVMのバグが原因である可能性が高いと言えます。特に、純粋なJavaの例を使用して取得できる場合。

(JVMは、クラスのロード時にコンパイラーやバイトコードベリファイアによって検出されるべきであったタイプセーフティの問題を報告しているようです。)

Java8のバグの推奨チャネルを介して報告してください。

于 2013-01-27T00:44:34.180 に答える
1

問題に直接関係するわけではありませんが、この方法で匿名クラスを使用しないことを強くお勧めします。2つの値を追加することのみを目的として、まったく新しいHashSetサブタイプを作成しています。これはシステムを肥大化させるだけでなく(メモリに永久に残ります)、呼び出しサイトでHashSetを表示するだけではないため、JVMのJITを混乱させる可能性があります...作成した多くのサブタイプの1つを表示します。

于 2014-01-18T16:28:41.157 に答える